1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Initial Developer of the Original Code is Fireinput Inc.
15 *
16 * Portions created by the Initial Developer are Copyright (C) 2007
17 * the Initial Developer. All Rights Reserved.
18 *
19 * Contributor(s):
20 * Olly Ja <ollyja@gmail.com>
21 *
22 * Alternatively, the contents of this file may be used under the terms of
23 * either the GNU General Public License Version 2 or later (the "GPL"), or
24 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
25 * in which case the provisions of the GPL or the LGPL are applicable instead
26 * of those above. If you wish to allow use of your version of this file only
27 * under the terms of either the GPL or the LGPL, and not to allow others to
28 * use your version of this file under the terms of the MPL, indicate your
29 * decision by deleting the provisions above and replace them with the notice
30 * and other provisions required by the GPL or the LGPL. If you do not delete
31 * the provisions above, a recipient may use your version of this file under
32 * the terms of any one of the MPL, the GPL or the LGPL.
33 *
34 * ***** END LICENSE BLOCK *****
35 */
36 var imeInterfaceUI = [
37 {id: "fireinputToggleHalfButton", strKey: "fireinput.toggle.half.button", attribute: "tooltiptext"},
38 {id: "fireinputTogglePunctButton", strKey: "fireinput.toggle.punct.button", attribute: "tooltiptext"},
39 {id: "fireinputToggleIMEButton", strKey: "fireinput.toggle.ime.button", attribute: "tooltiptext"},
40 {id: "fireinputPrevSelButton", strKey: "fireinput.previous.selection", attribute: "tooltiptext"},
41 {id: "fireinputNextSelButton", strKey: "fireinput.next.selection", attribute: "tooltiptext"},
42 {id: "fireinputLongPrevSelButton", strKey: "fireinput.previous.selection", attribute: "tooltiptext"},
43 {id: "fireinputLongNextSelButton", strKey: "fireinput.next.selection", attribute: "tooltiptext"},
44 {id: "fireinputContextEnhanceWordTable", strKey: "fireinput.wordtable.enhance", attribute: "label"},
45 {id: "fireinputContextEnableIME", strKey: "fireinput.show.IME", attribute: "label"},
46 {id: "fireinputContextSwitchEncoding", strKey: "fireinput.encoding.switch", attribute: "label"},
47 {id: "fireinputContextSwitchZHToBG", strKey: "fireinput.encoding.zhtobg", attribute: "label"},
48 {id: "fireinputContextSwitchBGToZH", strKey: "fireinput.encoding.bgtozh", attribute: "label"},
49 {id: "menuPinyinQuan", strKey: "fireinput.pinyin.quan.label", attribute: "label"},
50 {id: "menuPinyinShuangZiGuang", strKey: "fireinput.pinyin.shuang.ziguang.label", attribute: "label"},
51 {id: "menuPinyinShuangMS", strKey: "fireinput.pinyin.shuang.ms.label", attribute: "label"},
52 {id: "menuPinyinShuangChineseStar", strKey: "fireinput.pinyin.shuang.chinesestar.label", attribute: "label"},
53 {id: "menuPinyinShuangSmartABC", strKey: "fireinput.pinyin.shuang.smartabc.label", attribute: "label"},
54 {id: "menuWubi86", strKey: "fireinput.wubi86.label", attribute: "label"},
55 {id: "menuWubi98", strKey: "fireinput.wubi98.label", attribute: "label"},
56 {id: "fireinputIMEBarCloseButton", strKey: "fireinput.close.IME", attribute: "tooltiptext"},
57 {id: "fireinputSpecialCharMenu", strKey: "fireinput.special.char.label", attribute: "label"},
58 {id: "inputHistoryList", strKey: "fireinput.history.list", attribute: "label"},
59 {id: "fireinputHelp", strKey: "fireinput.help.label", attribute: "label"},
60 {id: "fireinputSearchButton", strKey: "fireinput.search.label", attribute: "value"},
61 {id: "fireinputContextSelectImage", strKey: "fireinput.context.select.image", attribute: "label"}
62 ];
63
64
65 var imeInputModeValues = [
66 {name: ENCODING_ZH, label: "fireinput.method.chinese.value"},
67 {name: ENCODING_BIG5, label: "fireinput.method.big5.value"},
68 {name: ENCODING_EN, label: "fireinput.method.english.value"}
69 ];
70
71
72 var Fireinput =
73 {
74 // debug: 0 disable, non-zero enable
75 debug: 0,
76 // Fireinput statusbar status
77 myRunStatus: false,
78 // IME mode. False for english mode, otherwise it's IME mode
79 myInputStatus: false,
80 // instance of IME
81 myIME: null,
82 // IME input bar stauts.
83 myIMEInputBarStatus: false,
84
85 // IME input field focused status. Popup/some key handling will be surpressed if it's true
86 myIMEInputFieldFocusedStatus: false,
87
88 // IME mode. The mode can ZH or EN. Chinese can only be typed under ZH mode
89 // Shortkey: type v if enable english mode, and space will resume original mode back
90 // reset by space /enter or target change
91 myIMEMode: IME_MODE_ZH,
92
93 // Input mode. It will decide which encoding will be used(Simplified Chinese or Big5)
94 myInputMode: ENCODING_ZH,
95
96 // table lookup delay timer
97 myKeyTimer: null,
98 // caret focus event
99 myEvent: null,
100 // caret focus target
101 myTarget: null,
102 // last input key chars before composing a new phrase
103 myInputChar: "",
104 // last selected element to be used repeatedly
105 myLastSelectedElementValue: "",
106 // save user typing history
107 mySaveHistory: true,
108 // auto insertion if there is one choice
109 myAutoInsert: false,
110 // is compose mode
111 myComposeEnabled: false,
112
113 // input bar position
114 myInputBarPos: null,
115
116 // half/full letter mode
117 myHalfMode: 0,
118
119 // half/full letter mode
120 myPunctMode: 0,
121
122 // allow Input Keys
123 myAllowInputKey: "",
124
125 // IME Schema
126 myIMESchema: SMART_PINYIN,
127
128 // long table
129 myLongTable: null,
130
131 // fireinput init function.
132 initialize: function()
133 {
134 FireinputPref.addObserver(this, false);
135 this.observeApplicationQuit();
136
137 // register event listener to trigger when context menu is invoked.
138 try
139 {
140 document.getElementById('contentAreaContextMenu').addEventListener('popupshowing',
141 fireinput_onPopupShowing,
142 false);
143 } catch(e) { }
144
145 // initialize the open hotkey
146 var handle = document.getElementById("key_enableFireinput");
147 var openKey = FireinputPrefDefault.getOpenKeyBinding();
148 if(/,/.test(openKey))
149 {
150 var openKeys = openKey.split(",");
151 if(handle) handle.setAttribute("modifiers", openKeys[0]);
152 if(handle) handle.setAttribute("keycode", openKeys[1]);
153 }
154
155 this.disableIMEMenu();
156 // initial default IME
157 this.myIME = this.getDefaultIME();
158
159 // load long table
160 FireinputLongTable.init();
161
162 // setup tooltips
163 this.loadIMEPref();
164
165 // initialize Pref interfaces
166 fireinputPrefInit();
167
168 this.loadIMEPrefByID("fireinputStatusBar", "fireinput.statusbar.tooltip.close", "tooltiptext");
169 this.loadIMEPrefByID("fireinputStatusBar", "fireinput.statusbar.tooltip.open", "tooltiptext");
170
171 },
172
173 observeApplicationQuit: function()
174 {
175 // register an observer
176 var os = Components.classes["@mozilla.org/observer-service;1"]
177 .getService(Components.interfaces.nsIObserverService);
178 os.addObserver(this, "quit-application-requested", false);
179 },
180
181 getDefaultIME: function(schema)
182 {
183 if(typeof(schema) == 'undefined')
184 this.myIMESchema = FireinputPrefDefault.getSchema();
185 else
186 this.myIMESchema = schema;
187
188 var ime = null;
189
190 switch(this.myIMESchema)
191 {
192 case WUBI_86:
193 case WUBI_98:
194 ime = new Wubi();
195 if(!ime.isEnabled())
196 return this.getDefaultIME(SMART_PINYIN);
197 break;
198 default:
199 ime = new SmartPinyin();
200 if(!ime.isEnabled() && typeof(schema) == 'undefined')
201 return this.getDefaultIME(WUBI_86);
202 break;
203 }
204
205 ime.setSchema(this.myIMESchema);
206 ime.loadTable();
207 this.myAllowInputKey = ime.getAllowedInputKey();
208 return ime;
209 },
210
211 disableIMEMenu: function()
212 {
213 var ime = new Wubi();
214 if(!ime.isEnabled())
215 {
216 var handle = document.getElementById("menuWubi86");
217 if(handle) handle.style.display = "none";
218 var handle = document.getElementById("imeWubi86");
219 if(handle) handle.style.display = "none";
220
221 var handle = document.getElementById("menuWubi98");
222 if(handle) handle.style.display = "none";
223 var handle = document.getElementById("imeWubi98");
224 if(handle) handle.style.display = "none";
225 }
226
227 ime = new SmartPinyin();
228 if(!ime.isEnabled())
229 {
230 var handle = document.getElementById("fireinputAMB");
231 if(handle) handle.style.display = "none";
232
233 var handle = document.getElementById("menuPinyinQuan");
234 if(handle) handle.style.display = "none";
235 var handle = document.getElementById("imePinyinQuan");
236 if(handle) handle.style.display = "none";
237
238 var handle = document.getElementById("menuPinyinShuangZiGuang");
239 if(handle) handle.style.display = "none";
240 var handle = document.getElementById("imePinyinShuangZiGuang");
241 if(handle) handle.style.display = "none";
242
243 var handle = document.getElementById("menuPinyinShuangMS");
244 if(handle) handle.style.display = "none";
245 var handle = document.getElementById("imePinyinShuangMS");
246 if(handle) handle.style.display = "none";
247
248 var handle = document.getElementById("menuPinyinShuangChineseStar");
249 if(handle) handle.style.display = "none";
250 var handle = document.getElementById("imePinyinShuangChineseStar");
251 if(handle) handle.style.display = "none";
252
253 var handle = document.getElementById("menuPinyinShuangSmartABC");
254 if(handle) handle.style.display = "none";
255 var handle = document.getElementById("imePinyinShuangSmartABC");
256 if(handle) handle.style.display = "none";
257 }
258 },
259
260 loadIMEPrefByID: function(id, strKey, attribute)
261 {
262 var defaultLanguage = FireinputPrefDefault.getInterfaceLanguage();
263
264 var value = FireinputUtils.getLocaleString(strKey + defaultLanguage);
265 var handle = document.getElementById(id);
266 if(!handle)
267 return;
268 if(id == "fireinputStatusBar")
269 {
270 value = FireinputKeyBinding.getOpenKeyStringReadable(value);
271 handle.setAttribute(strKey, value);
272 }
273
274 handle.setAttribute(attribute, value);
275 },
276
277 loadIMEPref: function(name)
278 {
279 // get default language first
280
281 if(!name || name == "interfaceLanguage")
282 {
283 var defaultLanguage = FireinputPrefDefault.getInterfaceLanguage();
284
285 // update UI
286 for(var i =imeInterfaceUI.length-1; i>=0; i--)
287 {
288 var id = imeInterfaceUI[i].id;
289 var strKey = imeInterfaceUI[i].strKey;
290 var attr = imeInterfaceUI[i].attribute;
291
292 var value = FireinputUtils.getLocaleString(strKey + defaultLanguage);
293 var handle = document.getElementById(id);
294 if(!handle)
295 continue;
296 handle.setAttribute(attr, value);
297 }
298
299 // update icon status text
300 if(this.myRunStatus)
301 this.loadIMEPrefByID("fireinputStatusBar", "fireinput.statusbar.tooltip.close", "tooltiptext");
302 else
303 this.loadIMEPrefByID("fireinputStatusBar", "fireinput.statusbar.tooltip.open", "tooltiptext");
304
305 // load the special char menu at the beginning
306 if(!name)
307 this.displaySpecialCharPanel();
308 else // refresh menu if language is changed
309 {
310 FireinputSpecialChar.refreshMenu();
311 FireinputEmotions.refreshMenu();
312 fireinputPrefInit();
313 }
314
315 this.loadIMEPrefByID("fireinputToggleIMEButton", "fireinput.method.chinese.value", "label");
316 }
317
318 //update value. The label of menu should be updated if language is changed
319 if(!name || name == "defaultInputMethod" || name == "interfaceLanguage")
320 {
321 var value = this.myIMESchema;
322 if(name == "defaultInputMethod")
323 value = FireinputPrefDefault.getSchema();
324
325 var element = document.getElementById("inputMethod");
326 if(value != null)
327 {
328 for(var index = 0; ; index++)
329 {
330 element.selectedIndex = index;
331 if(element.selectedIndex != -1)
332 {
333 if(element.selectedItem.style.display == "none")
334 continue;
335
336 if(element.selectedItem.value == value)
337 {
338 element.setAttribute("label", element.selectedItem.label);
339 // only toggle input method if the setting has been updated
340 if(name == "defaultInputMethod")
341 this.toggleInputMethod();
342 break;
343 }
344 }
345 else
346 break;
347 }
348 }
349 else
350 {
351 element.selectedIndex = 0;
352 element.setAttribute("label", element.selectedItem.label);
353 }
354 }
355
356 if(!name || name == "saveHistory")
357 {
358 this.mySaveHistory = FireinputPrefDefault.getSaveHistory();
359 }
360
361 if(!name || name == "autoInsert")
362 {
363 this.myAutoInsert = FireinputPrefDefault.getAutoInsert();
364 }
365 },
366
367
368 toggleFireinput: function(forceOpen)
369 {
370 var id = document.getElementById("fireinputIMEBar");
371 var toggleOff = forceOpen == undefined ? !id.hidden : !forceOpen;
372 id.hidden = toggleOff;
373 this.myRunStatus = !toggleOff;
374
375 if(!toggleOff)
376 {
377 var h = document.getElementById("fireinputStatusBar");
378 if(h && h.hasAttribute("fireinput.statusbar.tooltip.close"))
379 h.setAttribute("tooltiptext", h.getAttribute("fireinput.statusbar.tooltip.close"));
380 else
381 this.loadIMEPrefByID("fireinputStatusBar", "fireinput.statusbar.tooltip.close", "tooltiptext");
382
383 window.addEventListener('keypress', fireinput_onKeyPress, true);
384 window.addEventListener('keydown', fireinput_onKeyDown, true);
385 window.addEventListener('keyup', fireinput_onKeyUp, true);
386 this.myInputStatus = true;
387 this.setInputMode(ENCODING_ZH);
388 this.displayAjaxService();
389 }
390 else
391 {
392 // close the IME inputbar
393 if(this.myIMEInputBarStatus)
394 {
395 this.hideAndCleanInput();
396 }
397 this.resetIME();
398
399 var h = document.getElementById("fireinputStatusBar");
400 if(h && h.hasAttribute("fireinput.statusbar.tooltip.open"))
401 h.setAttribute("tooltiptext", h.getAttribute("fireinput.statusbar.tooltip.open"));
402 else
403 this.loadIMEPrefByID("fireinputStatusBar", "fireinput.statusbar.tooltip.open", "tooltiptext");
404 window.removeEventListener('keypress', fireinput_onKeyPress, true);
405 window.removeEventListener('keydown', fireinput_onKeyDown, true);
406 window.removeEventListener('keyup', fireinput_onKeyUp, true);
407 }
408 },
409
410 disableIME: function()
411 {
412 if(!this.myRunStatus)
413 return;
414 // if it's input enabled, disable it and turn off keypress listener
415 if(this.myInputStatus)
416 {
417 this.hideAndCleanInput();
418 this.resetIME();
419 window.removeEventListener('keypress', fireinput_onKeyPress, true);
420 window.removeEventListener('keydown', fireinput_onKeyDown, true);
421 window.removeEventListener('keyup', fireinput_onKeyUp, true);
422 }
423 },
424
425 enableIME: function()
426 {
427 if(!this.myRunStatus)
428 return;
429
430 if(!this.myInputStatus)
431 {
432 this.myInputStatus = true;
433 window.addEventListener('keypress', fireinput_onKeyPress, true);
434 window.addEventListener('keydown', fireinput_onKeyDown, true);
435 window.addEventListener('keyup', fireinput_onKeyUp, true);
436 }
437 },
438
439 toggleIME: function()
440 {
441 if(!this.myRunStatus)
442 return;
443
444 if(this.myInputStatus)
445 this.setInputMode(ENCODING_EN);
446 else
447 this.setInputMode(this.myInputMode);
448 },
449
450 resetIME: function ()
451 {
452 this.myInputStatus = false;
453 this.myIMEInputBarStatus = false;
454 },
455
456 toggleInputMethod: function()
457 {
458 // close the IME inputbar
459 if(this.myIMEInputBarStatus)
460 {
461 this.hideAndCleanInput();
462 }
463 this.myIMEInputBarStatus = false;
464
465 var method = document.getElementById("inputMethod").value;
466 if(this.myIMESchema == method)
467 return;
468
469 if((method == WUBI_86 || method == WUBI_98) &&
470 this.myIMESchema != method)
471 {
472 this.myIME = null;
473 this.myIME = new Wubi();
474 this.myIME.setSchema(method);
475 this.myIME.loadTable();
476 }
477 else if((this.myIMESchema == WUBI_86 || this.myIMESchema == WUBI_98) &&
478 method != this.myIMESchema)
479 {
480 this.myIME = null;
481 this.myIME = new SmartPinyin();
482 this.myIME.setSchema(method);
483 this.myIME.loadTable();
484 }
485 else
486 this.myIME.setSchema(method);
487
488 this.myIMESchema = method;
489
490 // enable zh input
491 this.setInputMode(ENCODING_ZH);
492
493 this.myAllowInputKey = this.myIME.getAllowedInputKey();
494 if(!this.myIME.isSchemaEnabled())
495 {
496 alert("火输中文输入: 对不起,此输入法字库没有安装,请到http://www.fireinput.com/forum/ 去下载字库");
497 return;
498 }
499 },
500
501 getModeString: function(mode)
502 {
503 for(var i=imeInputModeValues.length-1; i>=0; i--)
504 {
505 if(mode == imeInputModeValues[i].name)
506 return imeInputModeValues[i].label;
507 }
508
509 // otherwise return first one
510 return imeInputModeValues[0].label;
511
512 },
513
514 // set IME mode - not disable keyboard listening
515 setIMEMode: function(mode)
516 {
517 if(this.myIMEMode == mode)
518 return;
519
520 this.myIMEMode = mode;
521
522 switch(mode)
523 {
524 case IME_MODE_ZH:
525 var modeString = this.getModeString(this.myInputMode);
526 this.loadIMEPrefByID("fireinputToggleIMEButton", modeString, "label");
527 break;
528 case IME_MODE_EN:
529 var modeString = this.getModeString(mode);
530 this.loadIMEPrefByID("fireinputToggleIMEButton", modeString, "label");
531 break;
532 default:
533 return;
534 }
535 },
536
537 toggleIMEMode: function()
538 {
539 if(this.myIMEMode == IME_MODE_ZH)
540 this.setIMEMode(IME_MODE_EN);
541 else
542 this.setIMEMode(IME_MODE_ZH);
543 },
544
545 setInputMode: function(mode)
546 {
547 var modeString = this.getModeString(mode);
548 this.loadIMEPrefByID("fireinputToggleIMEButton", modeString, "label");
549 switch(mode)
550 {
551 case ENCODING_ZH:
552 case ENCODING_BIG5:
553 this.myInputMode = mode;
554 this.myIMEMode = IME_MODE_ZH;
555 this.myIME.setEncoding(mode);
556 this.enableIME();
557 break;
558 case ENCODING_EN:
559 this.myIMEMode = IME_MODE_EN;
560 this.disableIME();
561 break;
562 default:
563 return;
564 }
565 },
566
567 toggleInputMode: function()
568 {
569 if(this.myIMEMode == IME_MODE_EN)
570 {
571 this.setInputMode(ENCODING_ZH);
572 return;
573 }
574
575 switch(this.myInputMode)
576 {
577 case ENCODING_ZH:
578 this.setInputMode(ENCODING_BIG5);
579 break;
580
581 case ENCODING_BIG5:
582 this.setInputMode(ENCODING_EN);
583 break;
584 default:
585 this.setInputMode(ENCODING_ZH);
586 }
587 },
588
589 toggleHalfMode: function()
590 {
591 if(this.myIME.isHalfLetterMode())
592 {
593 var id = document.getElementById("fireinputToggleHalfButton");
594 if(id)
595 {
596 id.style.listStyleImage = "url('chrome://fireinput/skin/full-letter.png')";
597 this.myIME.setFullLetterMode();
598 }
599 }
600 else
601 {
602 var id = document.getElementById("fireinputToggleHalfButton");
603 if(id)
604 {
605 id.style.listStyleImage = "url('chrome://fireinput/skin/half-letter.png')";
606 this.myIME.setHalfLetterMode();
607 }
608
609 }
610 },
611
612 togglePunctMode: function()
613 {
614 if(this.myIME.isHalfPunctMode())
615 {
616 var id = document.getElementById("fireinputTogglePunctButton");
617 if(id)
618 {
619 id.style.listStyleImage = "url('chrome://fireinput/skin/full-punct.png')";
620 this.myIME.setFullPunctMode();
621 }
622 }
623 else
624 {
625 var id = document.getElementById("fireinputTogglePunctButton");
626 if(id)
627 {
628 id.style.listStyleImage = "url('chrome://fireinput/skin/half-punct.png')";
629 this.myIME.setHalfPunctMode();
630 }
631
632 }
633 },
634
635 onClickStatusIcon: function(event)
636 {
637 if (event.button != 0)
638 return;
639 this.toggleFireinput();
640 },
641
642 fireinputContext: function()
643 {
644 document.getElementById('fireinputContextEnableIME').hidden = !(gContextMenu.onTextInput);
645 document.getElementById('fireinputContextSelectImage').hidden = !(gContextMenu.onImage);
646 // init add table menu
647 var hidden = !(gContextMenu.isTextSelected);
648 if(!hidden)
649 {
650 var selectedText = FireinputLongTable.showSelection();
651 if(!selectedText)
652 {
653 document.getElementById('fireinputContextEnhanceWordTable').hidden = !hidden;
654 return;
655 }
656 var defaultLanguage = FireinputPrefDefault.getInterfaceLanguage();
657 var value = FireinputUtils.getLocaleString("fireinput.wordtable.enhance" + defaultLanguage);
658
659 var handle = document.getElementById('fireinputContextEnhanceWordTable');
660 label = value + '"' + selectedText + '"';
661 handle.setAttribute("label", label);
662 handle.hidden = hidden;
663 }
664 else
665 document.getElementById('fireinputContextEnhanceWordTable').hidden = hidden;
666 },
667
668 // all Observers
669 observe: function(subject, topic, data)
670 {
671 if(topic == "quit-application-requested")
672 {
673 if(this.myIME)
674 this.myIME.flushUserTable();
675 }
676
677 if(topic == "nsPref:changed")
678 {
679 var name = data.substr(prefDomain.length+1);
680 this.updatePref(name);
681 }
682 },
683
684 updatePref: function(name)
685 {
686 this.loadIMEPref(name);
687 },
688
689 // mouse down on input bar
690 inputBarMouseDownListener: function(event)
691 {
692 if(!this.myIMEInputBarStatus)
693 return;
694
695 // skip if it's char label
696 if(/fireinputIMEList/.test(event.target.id))
697 return;
698
699 this.myMouseDownEvent = true;
700 this.myInputBarPos.x2 = event.clientX;
701 this.myInputBarPos.y2 = event.clientY;
702 },
703
704 // mouse down on input bar
705 inputBarMouseMoveListener: function(event)
706 {
707 if(!this.myIMEInputBarStatus)
708 return;
709
710 // skip if it's char label
711 if(/fireinputIMEList/.test(event.target.id))
712 return;
713
714 if(!this.myMouseDownEvent)
715 return;
716
717 event.target.style.cursor = "move";
718
719 var id = document.getElementById("fireinputIMEContainer");
720
721 var mX = this.myInputBarPos.x + event.clientX - this.myInputBarPos.x2;
722 var mY = this.myInputBarPos.y + event.clientY - this.myInputBarPos.y2;
723
724 id.moveTo(mX, mY);
725 this.myInputBarPos = {x: mX, y: mY, x1: mX, y1: mY, x2: event.clientX, y2: event.clientY };
726 },
727
728 // mouse up on input bar
729 inputBarMouseUpListener: function(event)
730 {
731 if(!this.myIMEInputBarStatus)
732 return;
733
734 // skip if it's char label
735 if(/fireinputIMEList/.test(event.target.id))
736 return;
737
738 if(!this.myMouseDownEvent)
739 return;
740
741 event.target.style.cursor = "auto";
742 // clear the event
743 this.myMouseDownEvent = false;
744 },
745
746 enableComposeEditor: function(flag)
747 {
748 this.myComposeEnabled = flag;
749 },
750
751 isTargetATextBox : function ( node )
752 {
753 if(!node)
754 return 0;
755
756 if (node instanceof HTMLInputElement)
757 return (node.type == "text" || node.type == "password")
758
759 return (node instanceof HTMLTextAreaElement);
760 },
761
762 isValidTarget: function(event)
763 {
764 var documentTarget = false;
765 var target = event.explicitOriginalTarget
766 if(target == null)
767 target = event.target;
768
769 if(target == null || (target && target.type == "password"))
770 return {target: target, valid: false, documentTarget: documentTarget};
771
772 if(target instanceof XULElement && target.id == "urlbar")
773 return {target: target, valid: false, documentTarget: documentTarget};
774
775 if(!target.setSelectionRange)
776 {
777 var wrappedTarget = document.commandDispatcher.focusedElement;
778
779 if(wrappedTarget instanceof HTMLInputElement ||
780 wrappedTarget instanceof HTMLTextAreaElement)
781 {
782 if(!this.isTargetATextBox(wrappedTarget))
783 return {target: target, valid: false, documentTarget: documentTarget};
784 else if(wrappedTarget.tagName == 'html:input' || wrappedTarget.tagName == 'html:textarea')
785 {
786 //xul window input element
787 wrappedTarget.boxObject = target.boxObject;
788 if(wrappedTarget.type == 'password')
789 return {target: wrappedTarget, valid: false, documentTarget: documentTarget};
790 else
791 return {target: wrappedTarget, valid: true, documentTarget: documentTarget};
792 }
793
794 }
795 else
796 {
797 target = document.commandDispatcher.focusedWindow;
798 if (target) {
799 var editingSession = target.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
800 .getInterface(Components.interfaces.nsIWebNavigation)
801 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
802 .getInterface(Components.interfaces.nsIEditingSession);
803 if (!editingSession.windowIsEditable(target))
804 return {target: target, valid: false, documentTarget: documentTarget};
805
806 documentTarget = true;
807 }
808 }
809 }
810 else if(target.readOnly)
811 return {target: target, valid: false, documentTarget: documentTarget};
812
813 return {target: target, valid: true, documentTarget: documentTarget};
814 },
815
816 keyUpListener: function(event)
817 {
818 if(!this.myRunStatus || this.myIMEInputBarStatus)
819 return;
820
821 var target = this.isValidTarget(event);
822
823 if(!target.valid)
824 return;
825
826 if(event.keyCode == KeyEvent.DOM_VK_SHIFT && event.charCode == 0 && this.myChangeIMEModeEvent)
827 {
828 this.myChangeIMEModeEvent = false;
829 if(this.myIMEMode == IME_MODE_ZH)
830 {
831 this.setIMEMode(IME_MODE_EN);
832 return;
833 }
834 else
835 {
836 this.setIMEMode(IME_MODE_ZH);
837 return;
838 }
839 }
840 },
841
842 keyDownListener: function(event)
843 {
844 if(!this.myRunStatus)
845 return;
846
847 if(this.myIMEInputBarStatus)
848 {
849 // Add fix for FCKeditor enter key issue
850 if(event.keyCode == KeyEvent.DOM_VK_RETURN ||
851 event.keyCode == KeyEvent.DOM_VK_SPACE)
852 event.preventDefault();
853 event.stopPropagation();
854 return;
855 }
856
857 // focus search box event
858 if(event.keyCode == KeyEvent.DOM_VK_F4)
859 {
860 FireinputWebSearch.focusSearchbox();
861 return;
862 }
863
864 var target = this.isValidTarget(event);
865
866 if(!target.valid)
867 return;
868
869 if(event.keyCode == KeyEvent.DOM_VK_SHIFT && event.charCode == 0)
870 {
871 this.myChangeIMEModeEvent = true;
872 }
873 },
874
875 keyPressListener: function(event)
876 {
877
878 var targetInfo = this.isValidTarget(event);
879 if(!targetInfo.valid)
880 return;
881
882 var target = targetInfo.target;
883 var documentTarget = targetInfo.documentTarget;
884
885 var keyCode = event.keyCode;
886 var charCode = event.charCode;
887
888 // if shift key and other key has been pressed together, reset the IMEmode back
889 if(event.shiftKey && (event.altKey || event.ctrlKey || keyCode || charCode))
890 {
891 this.myChangeIMEModeEvent = false;
892 }
893
894 // we don't use alt/shift key
895 // should be used to handle the long list string
896 if(event.altKey && !event.shiftKey)
897 {
898 // handle ctrl + alt + f to insert Fireinput Ad
899 if(event.ctrlKey && String.fromCharCode(charCode) == 'f')
900 {
901 this.displayADString();
902 return;
903 }
904
905 if(keyCode == KeyEvent.DOM_VK_RETURN)
906 {
907 FireinputWebSearch.load();
908 return;
909
910 }
911 return;
912 }
913
914 // check some key if control is pressed
915 if(event.ctrlKey)
916 {
917 // ctrl + number: choose a long table
918 if(charCode > KeyEvent.DOM_VK_0 && charCode <= KeyEvent.DOM_VK_5)
919 {
920 FireinputLongTable.insertCharToTarget(String.fromCharCode(charCode));
921 }
922 return;
923 }
924
925
926
927 // ESC: clean up the input. Press twice will close input window
928 if(keyCode == KeyEvent.DOM_VK_ESCAPE)
929 {
930 if(this.myIMEInputBarStatus)
931 {
932 event.preventDefault();
933 event.stopPropagation();
934 this.hideAndCleanInput();
935 return;
936 }
937 return;
938 }
939
940 // HOME: display the first set of input (first 10)
941 if(keyCode == KeyEvent.DOM_VK_HOME)
942 {
943 if(!this.myIMEInputBarStatus)
944 return;
945
946 if(this.myComposeEnabled || this.myIMEInputFieldFocusedStatus)
947 return;
948
949 event.preventDefault();
950
951 this.prevSel("HOME");
952 return;
953 }
954
955 // END: display the last set of input (last 10)
956 if(keyCode == KeyEvent.DOM_VK_END)
957 {
958 if(!this.myIMEInputBarStatus)
959 return;
960
961 if(this.myComposeEnabled || this.myIMEInputFieldFocusedStatus)
962 return;
963
964 event.preventDefault();
965 this.nextSel("END");
966 return;
967 }
968
969 // F2: repeat the previous selection
970 // FireinputLog.debug(this,"keyCode:" + keyCode + ", charCode: " + charCode);
971 // FireinputLog.debug(this,"charCode string:" + String.fromCharCode(charCode));
972
973 // the IME mode needs to be reset if the target has changed
974 if(this.myTarget && this.myTarget.target != target)
975 this.setIMEMode(IME_MODE_ZH);
976
977 // keep the real event and target if inputfield has been focused
978 if(!this.myIMEInputFieldFocusedStatus && !this.myComposeEnabled)
979 {
980 this.myEvent = event;
981 this.myTarget = {target: target, documentTarget: documentTarget};
982 }
983
984 if(keyCode == KeyEvent.DOM_VK_F2)
985 {
986 if(this.myIMEInputBarStatus)
987 return;
988
989 event.preventDefault();
990 // FireinputLog.debug(this,"F2: " + this.myLastSelectedElementValue);
991 FireinputUtils.insertCharAtCaret(this.myTarget, this.myLastSelectedElementValue);
992 // add into long table
993 FireinputLongTable.addIntoLongTable(this.myTarget.target, this.myLastSelectedElementValue);
994
995 return;
996 }
997
998 // backspace: remove the input bar. If the input bar is empty, remove target value
999 if(keyCode == KeyEvent.DOM_VK_BACK_SPACE)
1000 {
1001 // inputField is focused
1002 if(this.myComposeEnabled)
1003 return;
1004
1005 if(this.myIMEInputFieldFocusedStatus && !FireinputComposer.hasSet())
1006 {
1007 return;
1008 }
1009
1010 var id = document.getElementById("fireinputIMEContainer");
1011 if(this.myIMEInputBarStatus)
1012 {
1013 var idf = document.getElementById("fireinputField");
1014 if(idf.value.length ==0 && !FireinputComposer.hasSet())
1015 {
1016 id.hidePopup();
1017 }
1018 else
1019 {
1020 event.preventDefault();
1021
1022 if(this.myInputChar.length > 0)
1023 {
1024 this.myInputChar = this.myInputChar.substring(0, this.myInputChar.length-1);
1025 idf.value = idf.value.substring(0, idf.value.length -1 );
1026 }
1027
1028 if(this.myInputChar.length <= 0)
1029 {
1030 var key = FireinputComposer.removeLastFromPanel();
1031 if(key)
1032 {
1033 idf.value = key;
1034 this.myInputChar = key;
1035 }
1036 else
1037 idf.value = "";
1038 }
1039
1040 if(idf.value.length ==0)
1041 {
1042 id.hidePopup();
1043 return;
1044 }
1045 this.findCharWithDelay();
1046 }
1047 }
1048
1049 return;
1050 }
1051
1052 // enter: select the highlight column. If the input bar is not activated, go to default action
1053 if(keyCode == KeyEvent.DOM_VK_RETURN)
1054 {
1055 if(!this.myIMEInputBarStatus)
1056 {
1057 FireinputLongTable.flushLongTable();
1058 return;
1059 }
1060
1061 if(this.myComposeEnabled)
1062 {
1063 this.insertCharToComposer(event, 1, "false");
1064 }
1065 else
1066 this.insertCharToTarget(event, this.myTarget, 1, true);
1067
1068 return;
1069 }
1070
1071 // page down for next
1072 if(keyCode == KeyEvent.DOM_VK_PAGE_DOWN)
1073 {
1074 if(this.myIMEInputBarStatus)
1075 {
1076 event.preventDefault();
1077 event.stopPropagation();
1078 this.nextSel();
1079 }
1080 return;
1081 }
1082 // page up for previous
1083 if(keyCode == KeyEvent.DOM_VK_PAGE_UP)
1084 {
1085 if(this.myIMEInputBarStatus)
1086 {
1087 event.preventDefault();
1088 event.stopPropagation();
1089 this.prevSel();
1090 }
1091
1092 return;
1093 }
1094
1095 // if it's not printable char, just return here
1096 if(charCode ==0)
1097 return;
1098
1099 var key = String.fromCharCode(charCode);
1100
1101
1102 // return here if the mode is non-chinese mode
1103 if(this.myIMEMode != IME_MODE_ZH)
1104 return;
1105
1106 // comma: display previous choice
1107 // in keypress event, this value won't match
1108 if(key == ',')
1109 {
1110 if(this.myIMEInputBarStatus)
1111 {
1112 event.preventDefault();
1113 this.prevSel();
1114 return;
1115 }
1116 }
1117
1118 // period: display next choice
1119 if(key == '.')
1120 {
1121 if(this.myIMEInputBarStatus)
1122 {
1123 event.preventDefault();
1124 this.nextSel();
1125 return;
1126 }
1127 }
1128 // space to insert first one
1129 if(charCode == KeyEvent.DOM_VK_SPACE)
1130 {
1131 if(this.myIMEInputBarStatus)
1132 {
1133 if(this.myComposeEnabled)
1134 {
1135 this.insertCharToComposer(event, 1, "false");
1136 }
1137 else
1138 this.insertCharToTarget(event, this.myTarget, 1, true);
1139 return;
1140 }
1141 // return here otherwise some rich editor might be broken
1142 return;
1143 }
1144
1145 // 1..2..9
1146 if(charCode > KeyEvent.DOM_VK_0 && charCode <= KeyEvent.DOM_VK_9)
1147 {
1148 if(this.myIMEInputBarStatus)
1149 {
1150 FireinputLog.debug(this, "this.myComposeEnabled: " + this.myComposeEnabled + ", press number key: " + key);
1151 if(this.myComposeEnabled || FireinputComposer.hasSet())
1152 {
1153 this.insertCharToComposer(event, key, "false");
1154 }
1155 else
1156 this.insertCharToTarget(event, this.myTarget, key, true);
1157
1158 return;
1159 }
1160 }
1161
1162 // small case a-z
1163 if(this.myAllowInputKey.indexOf(key) >= 0 && !event.shiftKey)
1164 {
1165 // inputField is enabled, allow the input and send delay searching
1166 if(this.myIMEInputFieldFocusedStatus || this.myComposeEnabled)
1167 {
1168 return;
1169 }
1170
1171 event.preventDefault();
1172 // open IME input window
1173
1174 if(!this.myIMEInputBarStatus)
1175 {
1176 var xpos = 0;
1177 var ypos = 0;
1178 if(target.boxObject)
1179 {
1180 var id = document.getElementById("fireinputIMEContainer");
1181 id.showPopup(target, -1, -1, "popup", "bottomleft", "topleft");
1182 }
1183 else if(!documentTarget)
1184 {
1185 // HTML input/textarea element
1186 xpos = FireinputUtils.findPosX(target) -
1187 FireinputUtils.getDocumentScrollLeft(document.commandDispatcher.focusedWindow);
1188 ypos = FireinputUtils.findPosY(target) -
1189 FireinputUtils.getDocumentScrollTop(document.commandDispatcher.focusedWindow);
1190
1191 //FireinputLog.debug(this,"xpos: " + xpos + ",ypos: " + ypos);
1192
1193 xpos += window.screenX + 10;
1194 ypos += window.screenY + 20;
1195 if(ypos > (window.innerHeight - 20))
1196 ypos = window.innerHeight - 20;
1197
1198 if(ypos <= 20)
1199 ypos = 20;
1200
1201 FireinputLog.debug(this,"xpos:" + xpos);
1202 FireinputLog.debug(this,"ypos:" + ypos);
1203 FireinputLog.debug(this,"window.screenY:" + window.screenY);
1204 FireinputLog.debug(this,"window.screenX: " + window.screenX);
1205 FireinputLog.debug(this,"window.innerHeight:" + window.innerHeight);
1206 //FireinputLog.debug(this,"window.innerWidth:" + window.innerWidth);
1207 //FireinputLog.debug(this,"window.outerHeight:" + window.outerHeight);
1208 //FireinputLog.debug(this,"window.outerWidth:" + window.outerWidth);
1209 var id = document.getElementById("fireinputIMEContainer");
1210 id.showPopup(document.documentElement, xpos, ypos, "popup", null, null);
1211
1212 }
1213 else
1214 {
1215 // rich editor
1216 var p = target.frameElement;
1217 xpos = FireinputUtils.findPosX(p);
1218 ypos = FireinputUtils.findPosY(p);
1219 //FireinputLog.debug(this,"xpos: " + xpos + ",ypos: " + ypos);
1220 xpos = xpos - p.ownerDocument.body.scrollLeft;
1221 ypos = ypos - p.ownerDocument.body.scrollTop;
1222
1223 //FireinputLog.debug(this,"xpos: " + xpos + ",ypos: " + ypos);
1224
1225 xpos += window.screenX + 10;
1226 ypos += window.screenY + 20;
1227 if(ypos > (window.innerHeight - 20))
1228 ypos = window.innerHeight - 20;
1229
1230 if(ypos <= 20)
1231 ypos = 20;
1232
1233 FireinputLog.debug(this,"xpos:" + xpos);
1234 FireinputLog.debug(this,"ypos:" + ypos);
1235 FireinputLog.debug(this,"p.ownerDocument.documentElement:" + p.ownerDocument.documentElement);
1236 var id = document.getElementById("fireinputIMEContainer");
1237 id.showPopup(document.documentElement, xpos, ypos, "popup", null, null);
1238 }
1239 }
1240
1241 var idf = document.getElementById("fireinputField");
1242 this.myInputChar += key;
1243 idf.value += key;
1244
1245 this.findChar();
1246 return;
1247 }
1248
1249 // use single quot to separate pinyin input
1250 if(this.myIMEInputBarStatus)
1251 {
1252 if(key == "'" && (!this.myIMEInputFieldFocusedStatus || !this.myComposeEnabled))
1253 {
1254 var idf = document.getElementById("fireinputField");
1255 // only one is allowed
1256 if(idf.value.length > 0 && idf.value.substr(idf.value.length-1, 1) != "'")
1257 {
1258 event.preventDefault();
1259 this.myInputChar += key;
1260 idf.value += key;
1261 return;
1262 }
1263 }
1264
1265 // won't allow any other chars if IME inputfield is focused
1266 if(key != "'" && (this.myIMEInputFieldFocusedStatus || this.myComposeEnabled))
1267 event.preventDefault();
1268 }
1269
1270 // convert to Full width letters
1271 if(!this.myIMEInputBarStatus)
1272 {
1273 var fullLetter = this.myIME.convertLetter(charCode);
1274 if(typeof(fullLetter) == "object")
1275 {
1276 event.preventDefault();
1277 for (var s in fullLetter)
1278 {
1279 FireinputUtils.insertCharAtCaret(this.myTarget, fullLetter[s]);
1280 }
1281 }
1282 else if(typeof(fullLetter) != "undefined")
1283 {
1284 event.preventDefault();
1285 FireinputUtils.insertCharAtCaret(this.myTarget, fullLetter);
1286 }
1287
1288 // time to flush long table
1289 FireinputLongTable.flushLongTable();
1290 }
1291
1292 },
1293
1294 sendStringToPanel: function(codeArray, inputKey)
1295 {
1296 if(!codeArray || codeArray.length <= 0)
1297 {
1298 this.hideChars();
1299 return;
1300 }
1301
1302 var inputPanelElement = document.getElementById('fireinputIMEList');
1303 // FireinputLog.debug(this,"codeArray: " + this.myIME.getKeyWord(codeArray));
1304 var codeArrayLength = codeArray.length;
1305 for (var i = 0; i < codeArrayLength; i++)
1306 {
1307 var codeValue = "";
1308 if(typeof(codeArray[i].encodedWord) != 'undefined')
1309 codeValue = codeArray[i].encodedWord.replace(/[\d\.]+/g, '');
1310 else
1311 codeValue = FireinputUnicode.getUnicodeString(codeArray[i].word.replace(/[\d\.]+/g, ''));
1312
1313 var elementId = "fireinputIMEList_label" + (i+1);
1314 if(document.getElementById(elementId))
1315 {
1316 var element = document.getElementById(elementId);
1317 element.setAttribute("value", (i+1) + '.' + codeValue);
1318 element.setAttribute("tooltiptext", "键: " + codeArray[i].key+"/右点搜索“"+codeValue+"”");
1319 element.setAttribute("hiddenvalue", codeValue);
1320 element.setAttribute("hiddenkey", codeArray[i].key);
1321 element.setAttribute("hiddeninputkey", inputKey);
1322 element.setAttribute("hiddenword", codeArray[i].word);
1323 continue;
1324 }
1325
1326 var element = document.createElement("label");
1327 element.setAttribute("value", (i+1) + '.' + codeValue);
1328 element.setAttribute("tooltiptext", "键: " + codeArray[i].key+"/右点搜索“"+codeValue+"”");
1329 element.setAttribute("hiddenvalue", codeValue);
1330 element.setAttribute("hiddenkey", codeArray[i].key);
1331 element.setAttribute("hiddeninputkey", inputKey);
1332 element.setAttribute("hiddenword", codeArray[i].word);
1333 element.setAttribute("id", elementId);
1334 element.setAttribute("class", "charinputlabel");
1335 var self = this;
1336 element.onclick = function(event) { self.insertCharToComposerByMouse(event);};
1337 inputPanelElement.appendChild(element);
1338 }
1339
1340 // hide all other values
1341 this.hideChars(codeArray.length);
1342
1343 // check whether it needs to enable auto insertion
1344 if(this.myAutoInsert && this.myIME.canAutoInsert() && codeArray.length == 1)
1345 this.insertCharToTarget(this.myEvent, this.myTarget, 1, true);
1346
1347 // add long table to panel
1348 FireinputLongTable.addToPanel();
1349 },
1350
1351 hideAndCleanInput: function()
1352 {
1353 var idf = document.getElementById("fireinputField");
1354 idf.value = "";
1355 this.myInputChar = "";
1356
1357
1358 // hide all old chars
1359 this.hideChars(0);
1360 if(this.myIMEInputBarStatus)
1361 {
1362 var id = document.getElementById("fireinputIMEContainer");
1363 id.hidePopup();
1364 }
1365 },
1366
1367
1368 hideChars: function(start)
1369 {
1370 start = start || 0;
1371
1372 for (var i = 9; i >= start; i--)
1373 {
1374 var elementId = "fireinputIMEList_label" + (i+1);
1375 if(document.getElementById(elementId))
1376 {
1377 var element = document.getElementById(elementId);
1378 element.setAttribute("value", "");
1379 element.setAttribute("hiddenvalue", "");
1380 element.setAttribute("hiddenkey", "");
1381 element.setAttribute("hiddenword", "");
1382 element.setAttribute("hiddeninputkey", "");
1383 }
1384 }
1385 },
1386
1387 getCharByMouse: function (event)
1388 {
1389 var clickTarget = event.target;
1390 var elementId = clickTarget.getAttribute("id");
1391 return this.getCharByPos(elementId);
1392 },
1393
1394 getCharByPos: function(i)
1395 {
1396 if(this.myIMEInputBarStatus)
1397 {
1398 var elementName = "fireinputIMEList_label" + i;
1399 if(/fireinputIMEList_label/.test(i))
1400 elementName = i;
1401
1402 var elementId = document.getElementById(elementName);
1403 if(!elementId)
1404 return null;
1405
1406
1407 var value = elementId.getAttribute("hiddenvalue");
1408 var key = elementId.getAttribute("hiddenkey");
1409 var inputkey = elementId.getAttribute("hiddeninputkey");
1410 var word = elementId.getAttribute("hiddenword");
1411 if(value.length <= 0 || key.length <= 0 || word.length <= 0 ||inputkey.length <= 0)
1412 return null;
1413
1414 word = word.match(/[\D\.]+/g)[0];
1415 return {inputkey: inputkey, key: key, value: value, word: word };
1416 }
1417
1418 return null;
1419
1420 },
1421
1422 insertCharToComposer: function (event, i, cas)
1423 {
1424 if(event)
1425 {
1426 event.preventDefault();
1427 event.stopPropagation();
1428 }
1429
1430 var result = this.getCharByPos(i);
1431 var composeWasEnabled = this.myComposeEnabled;
1432 FireinputLog.debug(this, "result: " + result + ", this.myComposeEnabled:" + this.myComposeEnabled);
1433 if(result)
1434 {
1435 FireinputComposer.addToPanel(cas, result);
1436 if(!composeWasEnabled)
1437 {
1438 // remove idf.value
1439 var idf = document.getElementById("fireinputField");
1440 idf.value = "";
1441 // from event. Should not keep the global value
1442 if(event)
1443 {
1444 this.myInputChar = "";
1445 }
1446 }
1447
1448 if(composeWasEnabled)
1449 {
1450 FireinputUtils.setFocus(this.myTarget.target);
1451 }
1452 }
1453
1454
1455 },
1456
1457 insertCharToComposerByMouse: function (event)
1458 {
1459 var result = this.getCharByMouse(event);
1460
1461 // right click to launch search
1462 if(event.button == 2)
1463 {
1464 FireinputWebSearch.loadByMouse(result.value);
1465 return;
1466 }
1467
1468 if(!this.myIME.canComposeNew() || !FireinputComposer.hasSet())
1469 {
1470 this.insertCharToTargetByValue(result.value);
1471 this.hideAndCleanInput();
1472 return;
1473 }
1474
1475 var composeWasEnabled = this.myComposeEnabled;
1476
1477 if(result)
1478 {
1479 FireinputComposer.addToPanel("false", result);
1480 }
1481
1482 if(composeWasEnabled)
1483 {
1484 FireinputUtils.setFocus(this.myTarget.target);
1485 }
1486
1487 // remove idf.value
1488 var idf = document.getElementById("fireinputField");
1489 idf.value = "";
1490 this.myInputChar = "";
1491 },
1492
1493 insertCharToTargetByValue: function (charstr)
1494 {
1495 FireinputUtils.insertCharAtCaret(this.myTarget, charstr);
1496 // add into long table
1497 FireinputLongTable.addIntoLongTable(this.myTarget.target,charstr);
1498 },
1499
1500 insertCharToTarget: function (event, target, i, hideInput)
1501 {
1502 if(this.myIMEInputBarStatus)
1503 {
1504 event.preventDefault();
1505 event.stopPropagation();
1506
1507 var elementName;
1508 if(/fireinputIMEList_label/.test(i))
1509 elementName = i;
1510 else
1511 elementName = "fireinputIMEList_label" + i;
1512 var elementId = document.getElementById(elementName);
1513 if(!elementId || this.myInputChar.length <= 0 )
1514 {
1515 this.insertAllCharsToTarget(target, hideInput);
1516 return;
1517 }
1518
1519 var value = elementId.getAttribute("hiddenvalue");
1520 var key = elementId.getAttribute("hiddenkey");
1521 var word = elementId.getAttribute("hiddenword");
1522 if(value.length <= 0 || key.length <= 0 || word.length <= 0)
1523 {
1524 this.insertAllCharsToTarget(target, hideInput);
1525 return;
1526 }
1527
1528 this.insertAllCharsToTarget(target, hideInput, {key: key, word: word, value: value});
1529 }
1530 },
1531
1532 insertAllCharsToTarget: function (target, hideInput, keyWordResult)
1533 {
1534 if(this.myIMEInputBarStatus)
1535 {
1536 var value = "";
1537 var key = "";
1538 var word = "";
1539 if(keyWordResult)
1540 {
1541 value = keyWordResult.value;
1542 key = keyWordResult.key;
1543 word = keyWordResult.word;
1544 }
1545
1546 var insertValue = value;
1547 var composeWord = FireinputComposer.getComposeWord();
1548 if(composeWord.key.length <= 0 && key.length <= 0)
1549 return;
1550
1551 insertValue = composeWord.value + insertValue;
1552
1553 // keep the last selected element to insert repeatedly
1554 this.myLastSelectedElementValue = insertValue;
1555 FireinputUtils.insertCharAtCaret(target, insertValue);
1556
1557 // hide the inputbar after everything is written
1558 if(hideInput)
1559 {
1560 // also clear off the input bar
1561 var idf = document.getElementById("fireinputField");
1562 idf.value = "";
1563 var id = document.getElementById("fireinputIMEContainer");
1564 id.hidePopup();
1565 }
1566 this.myInputChar = "";
1567
1568 // update the frequency or save as new word
1569 if(composeWord.key.length > 0)
1570 {
1571 var newPhraseArray = [];
1572
1573 newPhraseArray.push({key: composeWord.key + " " + key, word: composeWord.word + word});
1574 FireinputLog.debug(this, "newPhraseArray: " + composeWord.key + " " + key + ", word: " + composeWord.word + word);
1575 this.myIME.storeUserPhrase(newPhraseArray);
1576 }
1577 else
1578 this.myIME.updateFrequency(word, key);
1579
1580 FireinputLongTable.addIntoLongTable(target.target, insertValue);
1581 }
1582 },
1583
1584 IMEWindowHiding: function()
1585 {
1586 // restore the focus to target if inputfield has been focused
1587 FireinputLog.debug(this, "this.myComposeEnabled: " + this.myComposeEnabled);
1588 if(this.myIMEInputFieldFocusedStatus || this.myComposeEnabled)
1589 {
1590 FireinputUtils.setFocus(this.myTarget.target);
1591 }
1592
1593 FireinputComposer.reset();
1594 FireinputLongTable.hidePanel();
1595 this.myIMEInputBarStatus = false;
1596 this.myIMEInputFieldFocusedStatus = false;
1597 this.hideAndCleanInput();
1598 },
1599
1600 IMEWindowShown: function()
1601 {
1602 this.myIMEInputBarStatus = true;
1603 },
1604
1605 IMEInputFieldMouseEvent: function(event)
1606 {
1607 if(event.button == 2)
1608 {
1609 event.preventDefault();
1610 event.stopPropagation();
1611 this.hideAndCleanInput();
1612 return;
1613 }
1614
1615 if(event.button != 0)
1616 return;
1617
1618 this.myIMEInputFieldFocusedStatus = true;
1619 },
1620
1621 IMEInputFieldFocusEvent: function(event)
1622 {
1623 this.myIMEInputFieldFocusedStatus = true;
1624
1625 // don't do anything if there is no input char
1626 var idf = document.getElementById("fireinputField");
1627 if(idf.value.length <= 0)
1628 return;
1629
1630 this.findCharWithDelayAndValue();
1631 },
1632
1633 IMEInputFieldOnInputEvent: function(event)
1634 {
1635 if(!this.myIMEInputFieldFocusedStatus)
1636 return;
1637
1638 var idf = document.getElementById("fireinputField");
1639
1640 // search current composed string status
1641 // remove all after if one get changed
1642 if(idf.value.length <= 0)
1643 {
1644 var composedLastKey = FireinputComposer.removeLastFromPanel();
1645 idf.value = composedLastKey;
1646 this.myInputChar = composedLastKey;
1647 }
1648 else
1649 {
1650 this.myInputChar = idf.value;
1651 }
1652
1653 this.findCharWithDelayAndValue();
1654 },
1655
1656 prevSel: function (homeFlag)
1657 {
1658 if(!this.canPrevSel())
1659 return;
1660
1661 var idf = document.getElementById("fireinputField");
1662
1663 // send to IME method to query the string
1664 var result = this.myIME.prev(homeFlag);
1665 // FireinputLog.debug(this,"call prev, length: " + codeArray.length);
1666 if(!result || !result.charArray)
1667 this.disableSelButton(true, false);
1668 else if(homeFlag || this.myIME.isBeginning())
1669 this.disableSelButton(true, false);
1670 else
1671 this.disableSelButton(false, false);
1672
1673 if(result && result.charArray)
1674 this.sendStringToPanel(result.charArray, result.validInputKey);
1675 else
1676 this.sendStringToPanel(null, null);
1677 },
1678
1679 nextSel: function(endFlag)
1680 {
1681 if(!this.canNextSel())
1682 return;
1683
1684 var idf = document.getElementById("fireinputField");
1685
1686 // send to IME method to query the string
1687 var result = this.myIME.next(endFlag);
1688 // FireinputLog.debug(this,"call next, length: " + codeArray.length);
1689 if(!result || !result.charArray || result.charArray.length < 9)
1690 this.disableSelButton(false, true);
1691 else if (endFlag || this.myIME.isEnd())
1692 this.disableSelButton(false, true);
1693 else
1694 this.disableSelButton(false, false);
1695
1696 if(result && result.charArray)
1697 this.sendStringToPanel(result.charArray, result.validInputKey);
1698 else
1699 this.sendStringToPanel(null, null);
1700 },
1701
1702 disableSelButton: function(prevFlag, nextFlag)
1703 {
1704 var button = document.getElementById("fireinputNextSelButton");
1705 if(nextFlag)
1706 button.disabled = true;
1707 else
1708 button.disabled = "";
1709
1710 button = document.getElementById("fireinputPrevSelButton");
1711 if(prevFlag)
1712 button.disabled = true;
1713 else
1714 button.disabled = "";
1715 },
1716
1717 canPrevSel: function()
1718 {
1719 var button = document.getElementById("fireinputPrevSelButton");
1720 return (!button.disabled);
1721 },
1722
1723 canNextSel: function()
1724 {
1725 var button = document.getElementById("fireinputNextSelButton");
1726 return (!button.disabled);
1727 },
1728
1729 // the function is used when inputField is focused
1730 findCharWithDelayAndValue: function()
1731 {
1732 if(this.myKeyTimer)
1733 clearTimeout(this.myKeyTimer);
1734 var idf = document.getElementById("fireinputField");
1735 if(idf.value.length ==0)
1736 {
1737 this.hideAndCleanInput();
1738 return;
1739 }
1740
1741 var self = this;
1742 // FireinputLog.debug(this, "this.myInputChar: " + this.myInputChar);
1743 this.myKeyTimer = setTimeout(function () { self.findChar(); }, 100);
1744 },
1745
1746 findCharWithDelay: function(delayMSec)
1747 {
1748 if(typeof(delayMSec) == 'undefined')
1749 delayMSec = 100;
1750 if(this.myKeyTimer)
1751 clearTimeout(this.myKeyTimer);
1752 var self = this;
1753 this.myKeyTimer = setTimeout(function () { self.findChar(); }, delayMSec);
1754 },
1755
1756 findChar: function()
1757 {
1758 if(this.myInputChar.length <= 0)
1759 return;
1760
1761 // FireinputLog.debug(this, "Send key: " + this.myInputChar + " => IME engine");
1762 // FireinputLog.debug(this, "myIMEInputFieldFocusedStatus: " + this.myIMEInputFieldFocusedStatus);
1763
1764 // send to IME method to query the string
1765 var result = this.myIME.find(this.myInputChar);
1766 this.sendStringToPanel(result.charArray, result.validInputKey);
1767 if(!result.charArray || result.charArray.length < 9)
1768 this.disableSelButton(true, true);
1769 else if (this.myIME.isEnd())
1770 this.disableSelButton(true, true);
1771 else
1772 this.disableSelButton(true, false);
1773
1774 if(!this.myIME.canComposeNew())
1775 return;
1776
1777 FireinputLog.debug(this, "Send key: " + this.myInputChar);
1778 if(result && result.charArray && result.charArray.length > 0 &&
1779 this.myInputChar.length > result.validInputKey.length)
1780 {
1781 var newvalue = this.myInputChar.substr(result.validInputKey.length, this.myInputChar.length);
1782 this.myInputChar = newvalue;
1783 this.insertCharToComposer(null, 1, "true");
1784 var idf = document.getElementById("fireinputField");
1785 idf.value = newvalue;
1786 this.findChar();
1787 }
1788 FireinputLog.debug(this, "after findChar, this.myInputChar: " + this.myInputChar);
1789
1790 },
1791
1792 findCharWithKey: function(inputChar)
1793 {
1794 if(!inputChar || inputChar.length <= 0)
1795 return;
1796
1797 FireinputLog.debug(this, "Send key: inputChar: " + inputChar);
1798
1799 // send to IME method to query the string
1800 var result = this.myIME.find(inputChar);
1801 this.sendStringToPanel(result.charArray, result.validInputKey);
1802 if(!result.charArray || result.charArray.length < 9)
1803 this.disableSelButton(true, true);
1804 else if (this.myIME.isEnd())
1805 this.disableSelButton(true, true);
1806 else
1807 this.disableSelButton(true, false);
1808 },
1809
1810 displaySpecialCharPanel: function()
1811 {
1812 var element = document.getElementById("fireinputSpecialCharMenuItems");
1813 FireinputSpecialChar.addGroup(element);
1814 },
1815
1816 displayAjaxService: function()
1817 {
1818 FireinputEmotions.load();
1819 FireinputHelp.load();
1820 },
1821
1822 insertSpecialCharAt: function(event, sourceType)
1823 {
1824 var clickTarget = event.target;
1825 // FireinputLog.debug(this, "value=" + clickTarget.value);
1826
1827 var target = document.commandDispatcher.focusedElement;
1828 var documentTarget = false;
1829 if(target)
1830 {
1831 if(!this.isTargetATextBox(target))
1832 return;
1833 }
1834 else
1835 {
1836 // editable DOM document(iframe:designMode=On)
1837 target = document.commandDispatcher.focusedWindow;
1838 if (target) {
1839 var editingSession = target.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
1840 .getInterface(Components.interfaces.nsIWebNavigation)
1841 .QueryInterface(Components.interfaces.nsIInterfaceRequestor)
1842 .getInterface(Components.interfaces.nsIEditingSession);
1843 if (!editingSession.windowIsEditable(target))
1844 return;
1845
1846 documentTarget = true;
1847 }
1848 }
1849
1850 var inputTarget = {target: target, documentTarget: documentTarget};
1851
1852 var value = clickTarget.getAttribute("hiddenvalue");
1853 if(!value)
1854 value = clickTarget.getAttribute("value");
1855
1856 FireinputUtils.insertCharAtCaret(inputTarget, value, sourceType);
1857 },
1858
1859 displayADString: function()
1860 {
1861 var ADString = "\n——————————————————————————\n";
1862 ADString += "火输中文输入法(Fireinput.com)";
1863 FireinputUtils.insertCharAtCaret(this.myTarget, ADString);
1864 }
1865
1866
1867 };
1868
1869 // Create event listener.
1870 window.addEventListener('load', fireinput_onLoad, false);
1871
1872
1873
1874 // event handlers
1875 function fireinput_onLoad()
1876 {
1877 Fireinput.initialize();
1878 }
1879
1880 function fireinput_onKeyUp(event)
1881 {
1882 Fireinput.keyUpListener(event);
1883 }
1884
1885 function fireinput_onKeyDown(event)
1886 {
1887 Fireinput.keyDownListener(event);
1888 }
1889 function fireinput_onKeyPress(event)
1890 {
1891 Fireinput.keyPressListener(event);
1892 }
1893
1894 function fireinput_onPopupShowing(event)
1895 {
1896 Fireinput.fireinputContext(event);
1897 }
1898
1899 function fireinput_onMouseDown(event)
1900 {
1901 Fireinput.inputBarMouseDownListener(event);
1902 }
1903
1904 function fireinput_onMouseMove(event)
1905 {
1906 Fireinput.inputBarMouseMoveListener(event);
1907 }
1908
1909 function fireinput_onMouseUp(event)
1910 {
1911 Fireinput.inputBarMouseUpListener(event);
1912 }
syntax highlighted by Code2HTML, v. 0.9.1