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