diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..aa6db20 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,104 @@ +Until version 20061001, the version number indicated the extension's release +date. Starting with the 20080224.x series, the first part indicates the version +of avim.js that the extension was based on, while the remaining version part +indicates the version of the extension itself, expressed as a Subversion +revision number. + +Version 20060714 (Friday, July 14, 2006) + - Initial release. + +Version 20061001 (Sunday, October 1, 2006) + - Integrated with the latest version of the AVIM script. + +Version 20080224.59 (Monday, June 16, 2008) + - First release by Minh Nguyen, based on a refactored codebase by Hieu Dang. + - Added support for Firefox 3 and removed support for Firefox 2. + - Replaced the status bar radio buttons with an unobtrusive popup menu. + - Added an identical menu under the Edit menu, for those who hide their status + bars. + - Added support for windows other than the main browser window, including the + Bookmark Properties dialog, the Library window, JavaScript prompt() dialogs, + and any other XUL document affected by an overlay listed in chrome.manifest. + The about:config filter bar and the Error Console code bar are not supported. + - Removed keyboard shortcuts that conflicted with built-in shortcuts and other + extensions. + - Replaced the "Off" "input method" with a separate "Enabled" option. + - Added the Ctrl+Shift+V keyboard shortcut (Cmd+Shift+V on the Mac) to toggle + AVIM on and off; this shortcut does not conflict with any built-in shortcuts, + but does conflict with Adblock Plus. + - Replaced the avim_prefs plain text preferences file with entries in Firefox's + built-in preferences service. Users of previous versions will have to set + their input method and other options again. + - Advanced options can be set using about:config. These options are: the IDs of + text boxes that AVIM should ignore and the actual methods that comprise Auto. + - Ensured that any preference change is reflected in every open window, as + well as windows opened from that point on. + - Localized into Spanish, because Minh knows Spanish. + - Localized into Vietnamese, in case Firefox ever gets an official translation + into Vietnamese. One can hope... + +Version 20080224.66 (Thursday, June 19, 2008) + - Fixed the checkbox menu items, which were completely broken. + - Added option to show and hide the status bar panel. + +Version 20080224.87 (Wednesday, July 2, 2008) + - Added a preference window that currently covers all the options available + through about:config. + - Added toolbar buttons for enabling and disabling AVIM and for choosing the + input method. The buttons can be added to the toolbar using the Customize + Toolbar dialog box. + - Added support for AJAX applications like Gmail and rich text editors like + FCKeditor. More testing is needed, however. + - Fixed issue where AVIM would ignore words following certain punctuation + characters, such as curly quotes and ellipses. + - Changed keyboard shortcut for toggling AVIM to Ctrl+Alt+V (Cmd+Opt+V on the + Mac) to avoid a collision with Adblock Plus. + - Added the Ctrl+: (Cmd+:) and Ctrl+; (Cmd+;) keyboard shortcuts to cycle back + and forward through the input method list. + - Added the Ctrl+Alt+S (Cmd+Opt+S) keyboard shortcut to toggle the "Enforce + Spelling" option. + - Added the Ctrl+Alt+; (Cmd+Opt+;) keyboard shortcut to toggle the "Old + Accents" option. + - Removed the menu item to toggle the status bar panel, since it is redundant + with the preference window now. + +Version 20080224.91 (Thursday, July 3, 2008) + - Added a warning that indicates when Mudim is enabled and turned on, along + with a button to turn Mudim off (as opposed to disabling the extension). + Mudim often interferes with AVIM, since the two extensions serve the same + purpose. + - Optimized the toolbar button images. + +Version 20080224.93 (Friday, July 4, 2008) + - Updated home page to point to 1ec5.org. + - Made ignored textbox IDs case-insensitive. + +Version 20080224.96 (Saturday, July 5, 2008) + - Fixed an issue where Mudim would not be turned off after the Disable Mudum + button is pressed. + - Added support for the Pencil extension. + - Fixed an issue where the status bar panel would not work in ChatZilla. + +Version 20080224.110 (Sunday, July 13, 2008) + - Added a "script monitor", which fixes compatibility issues with the AVIM/HIM, + VietTyping, and VietUni scripts by turning off any instances of them when + typing in a webpage. + - Added a preference to disable the script monitor, in case it causes + performance issues. + - Forced ignored textbox IDs to lowercase. + - Cleared ID textbox after the ID is ignored. + - Fixed encoding issues that prevented the Vietnamese locale from loading. + +Version ${Version} (${Date}) + - Added an option to allow words that begin with "dz" or "f", even when + spelling rules are enforced. + - Added support for more rich text editors, including Dojo's Dijit.Editor. + - Added support for disabling some versions of mViet. + - Added support for disabling the CHIM and Mudim scripts when typing in a + webpage. The two scripts are not disabled by default. + - Added explicit menu items for switching to the previous and next input + methods. Previously, keys for cycling methods would move around as the input + method changed, but this approach caused problems in Mac OS X. + - Options such as input method can no longer be changed when AVIM is disabled. + Before, the menu items for these options were disabled, but the keyboard + shortcuts were still active. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5aa7272 --- /dev/null +++ b/LICENSE @@ -0,0 +1,33 @@ +The file avim.js is subject to the following license: + +AVIM JavaScript Vietnamese Input Method Source File + +Copyright (C) 2004-2007 Hieu Tran Dang +Website: http://avim.veneroida.com/ + +You are allowed to use this software in any way you want providing: + 1. You must retain this copyright notice at all time + 2. You must not claim that you or any other third party is the author + of this software in any way. + +-------------------------------------------------------------------------------- +All other files are copyright (c) 2007-${Year} Minh Nguyen, subject to the +following license: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/TODO b/TODO new file mode 100644 index 0000000..9d8f124 --- /dev/null +++ b/TODO @@ -0,0 +1,18 @@ + - Scroll single-line textboxes to the side when AVIM modifies the input. + - Figure out why the first word entered into a designMode document is flipped + around (i.e., "DDa'nh" turns into "a'nhDD"). + - Add a preference to specify allowed initial consonant clusters, like mViet + does. [1] + - Support editable trees. [2] + - Add key mapping for the dong sign. + - Optionally remember on/off state per-site, using FUEL or the Content + Preferences service. [3] Maybe limit this feature to bookmarks (FUEL), since + the UI to set the preferences would be easier to figure out. + - The extension has some commented code towards supporting Thunderbird 3a1. The + main issues are identifying the myriad of textboxes that AVIM should ignore, + and finding a keyboard shortcut for toggling AVIM that won't conflict with + any of the shortcuts used on any of Thunderbird's windows. + +[1] http://www.dactai.com/mviet/mviet12AC/index.htm +[2] http://wiki.mozilla.org/XUL:Tree +[3] http://developer.mozilla.org/en/docs/Using_content_preferences diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..610b5e7 --- /dev/null +++ b/build.sh @@ -0,0 +1,154 @@ +#!/bin/bash +# build.sh -- builds JAR and XPI files for mozilla extensions +# by Nickolay Ponomarev +# (original version based on Nathan Yergler's build script) +# Most recent version is at + +# This script assumes the following directory structure: +# ./ +# chrome.manifest (optional - for newer extensions) +# install.rdf +# (other files listed in $ROOT_FILES) +# +# content/ | +# locale/ |} these can be named arbitrary and listed in $CHROME_PROVIDERS +# skin/ | +# +# defaults/ | +# components/ |} these must be listed in $ROOT_DIRS in order to be packaged +# ... | +# +# It uses a temporary directory ./build when building; don't use that! +# Script's output is: +# ./$APP_NAME.xpi +# ./$APP_NAME.jar (only if $KEEP_JAR=1) +# ./files -- the list of packaged files +# +# Note: It modifies chrome.manifest when packaging so that it points to +# chrome/$APP_NAME.jar!/* + +# +# default configuration file is ./config_build.sh, unless another file is +# specified in command-line. Available config variables: +APP_NAME= # short-name, jar and xpi files name. Must be lowercase with no spaces +CHROME_PROVIDERS= # which chrome providers we have (space-separated list) +CLEAN_UP= # delete the jar / "files" when done? (1/0) +ROOT_FILES= # put these files in root of xpi (space separated list of leaf filenames) +ROOT_DIRS= # ...and these directories (space separated list) +VAR_FILES= # files that need variable substitution (space separated list) +VERSION= # version number (string) +PRUNE_DIRS= # exclude files with these directories in their paths (space separated list) +BEFORE_BUILD= # run this before building (bash command) +AFTER_BUILD= # ...and this after the build (bash command) + +REV_NUM=118 + +if [ -z $1 ]; then + . ./config_build.sh +else + . $1 +fi + +if [ -z $APP_NAME ]; then + echo "You need to create build config file first!" + echo "Read comments at the beginning of this script for more info." + exit; +fi + +ROOT_DIR=`pwd` +TMP_DIR=build + +#uncomment to debug +#set -x + +# remove any left-over files from previous build +rm -f $APP_NAME.jar $APP_NAME.xpi files +rm -rf $TMP_DIR + +$BEFORE_BUILD + +mkdir -pv $TMP_DIR/chrome + +# generate the JAR file, excluding CVS and temporary files +JAR_FILE=$TMP_DIR/chrome/$APP_NAME.jar +echo "Generating $JAR_FILE..." +for CHROME_SUBDIR in $CHROME_PROVIDERS; do + find $CHROME_SUBDIR -path $PRUNE_DIRS -prune -o -type f -print | grep -v \~ >> files +done + +zip -0 -r $JAR_FILE `cat files` +# The following statement should be used instead if you don't wish to use the JAR file +#cp --verbose --parents `cat files` $TMP_DIR/chrome + +# prepare components and defaults +echo "Copying various files to $TMP_DIR folder..." +for DIR in $ROOT_DIRS; do + cp -rpv $DIR $TMP_DIR + rm -rf `find $TMP_DIR/ \( -name ".svn" -type d \) -o \( -name ".DS_Store" -type f \)` +# mkdir $TMP_DIR/$DIR +# FILES="`find $DIR -path $PRUNE_DIRS -prune -o -type f -print | grep -v \~`" +# echo $FILES >> files +# cp -pv $FILES $TMP_DIR +done + +# Copy other files to the root of future XPI. +for ROOT_FILE in $ROOT_FILES install.rdf chrome.manifest; do + cp -v $ROOT_FILE $TMP_DIR + if [ -f $ROOT_FILE ]; then + echo $ROOT_FILE >> files + fi +done + +cd $TMP_DIR + +if [ -n "$VAR_FILES" ]; then + REV_DATE="Tuesday, July 15, 2008" + REV_YEAR="2008" + echo "Substituting variables for version $VERSION, build r$REV_NUM on \ +$REV_DATE..." + for VAR_FILE in $VAR_FILES; do + if [ -f $VAR_FILE ]; then + perl -pi -e "s/\x24\x7BRev\x7D/$REV_NUM/" $VAR_FILE + perl -pi -e "s/\x24\x7BVersion\x7D/$VERSION/" $VAR_FILE + perl -pi -e "s/\x24\x7BDate\x7D/$REV_DATE/" $VAR_FILE + perl -pi -e "s/\x24\x7BYear\x7D/$REV_YEAR/" $VAR_FILE + fi + done +fi + +if [ -f "chrome.manifest" ]; then + echo "Preprocessing chrome.manifest..." + # You think this is scary? + #s/^(content\s+\S*\s+)(\S*\/)$/\1jar:chrome\/$APP_NAME\.jar!\/\2/ + #s/^(skin|locale)(\s+\S*\s+\S*\s+)(.*\/)$/\1\2jar:chrome\/$APP_NAME\.jar!\/\3/ + # + # Then try this! (Same, but with characters escaped for bash :) + #sed -i -r -E s/^\(content\\s+\\S*\\s+\)\(\\S*\\/\)$/\\1jar:chrome\\/$APP_NAME\\.jar\!\\/\\2/ chrome.manifest + #sed -i -r -E s/^\(skin\|locale\)\(\\s+\\S*\\s+\\S*\\s+\)\(.*\\/\)$/\\1\\2jar:chrome\\/$APP_NAME\\.jar\!\\/\\3/ chrome.manifest + perl -pi -e "s/^(content\s+\S*\s+)(\S*\/)$/\1jar:chrome\/$APP_NAME\.jar\!\/\2/" chrome.manifest + perl -pi -e "s/^(skin|locale)(\s+\S*\s+\S*\s+)(.*\/)$/\1\2jar:chrome\/$APP_NAME\.jar!\/\3/" chrome.manifest + + # (it simply adds jar:chrome/whatever.jar!/ at appropriate positions of chrome.manifest) +fi + +# generate the XPI file +echo "Generating $APP_NAME.xpi..." +zip -r ../$APP_NAME.xpi * +echo "Generating $APP_NAME-$VERSION.xpi..." +zip -r ../$APP_NAME-$VERSION.xpi * + +cd "$ROOT_DIR" + +echo "Cleanup..." +if [ $CLEAN_UP = 0 ]; then + # save the jar file + mv $TMP_DIR/chrome/$APP_NAME.jar . +else + rm ./files +fi + +# remove the working files +rm -rf $TMP_DIR +echo "Done!" + +$AFTER_BUILD diff --git a/chrome.manifest b/chrome.manifest new file mode 100755 index 0000000..c0bf958 --- /dev/null +++ b/chrome.manifest @@ -0,0 +1,99 @@ +content avim content/ + +locale avim en locale/en-US/ +locale avim es locale/es/ +locale avim vi locale/vi/ + +skin avim classic/1.0 skin/ + +overlay chrome://global/content/editMenuOverlay.xul chrome://avim/content/avim.xul +overlay chrome://global/content/commonDialog.xul chrome://avim/content/avim.xul + +### Firefox #################################################################### + +# overlay chrome://browser/content/browser.xul chrome://avim/content/avim.xul + +style chrome://browser/content/browser.xul chrome://avim/skin/avim.css +style chrome://global/content/customizeToolbar.xul chrome://avim/skin/avim.css + +# Bookmark Properties dialog, now part of Places +overlay chrome://browser/content/places/bookmarkProperties.xul chrome://avim/content/avim.xul +# overlay chrome://browser/content/places/editBookmarkOverlay.xul chrome://avim/content/avim.xul +# overlay chrome://browser/content/bookmarks/bookmarksProperties.xul chrome://avim/content/avim.xul +# Cookies list +# overlay chrome://browser/content/preferences/cookies.xul chrome://avim/content/avim.xul +# File > Open Location... +overlay chrome://browser/content/openLocation.xul chrome://avim/content/avim.xul +# Help > Report Broken Web Site... +overlay chrome://reporter/content/reportWizard.xul chrome://avim/content/avim.xul + +### Thunderbird ################################################################ + +# overlay chrome://messenger/content/messenger.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/messageWindow.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/folderProps.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/renameFolderDialog.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/AccountManager.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/FilterEditor.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/messengercompose/messengercompose.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/addressbook/addressbook.xul chrome://avim/content/avim.xul +# overlay chrome://messenger/content/addressbook/abEditCardDialog.xul chrome://avim/content/avim.xul +# overlay chrome://messenger-newsblog/content/feed-properties.xul chrome://avim/content/avim.xul +# overlay chrome://editor/content/EdImageProps.xul chrome://avim/content/avim.xul + +### ChatZilla ################################################################## + +overlay chrome://chatzilla/content/chatzilla.xul chrome://avim/content/avim.xul +# Preferences dialog +overlay chrome://chatzilla/content/config.xul chrome://avim/content/avim.xul + +### ColorZilla ################################################################# + +# Color Picker dialog +overlay chrome://colorzilla/content/colorzillaColorPickerDialog.xul chrome://avim/content/avim.xul +# Statusbar Format dialog +overlay chrome://colorzilla/content/colorzillaStatusbarFormat.xul chrome://avim/content/avim.xul + +### DOM Inspector ############################################################## + +overlay chrome://inspector/content/commandOverlay.xul chrome://avim/content/avim.xul + +# Find Nodes dialog +overlay chrome://inspector/content/viewers/dom/findDialog.xul chrome://avim/content/avim.xul +# Properties dialogs +overlay chrome://inspector/content/viewers/domNode/domNodeDialog.xul chrome://avim/content/avim.xul +# overlay chrome://inspector/content/viewers/accessibleTree/evalJSDialog.xul chrome://avim/content/avim.xul +# overlay chrome://inspector/content/viewers/jsObject/evalExprDialog.xul chrome://avim/content/avim.xul +# Insert Node dialog +overlay chrome://inspector/content/viewers/dom/insertDialog.xul chrome://avim/content/avim.xul + +### Nightly Tester Tools ####################################################### + +# Options dialog +overlay chrome://nightly/content/options/options.xul chrome://avim/content/avim.xul + +### Pencil ##################################################################### + +overlay chrome://pencil/content/UI/Window.xul chrome://avim/content/avim.xul + +### ScrapBook ################################################################## + +# Item Properties dialog +overlay chrome://scrapbook/content/property.xul chrome://avim/content/avim.xul +# Manage Items dialog +overlay chrome://scrapbook/content/manage.xul chrome://avim/content/avim.xul + +### SQLite Manager ############################################################# + +overlay chrome://sqlitemanager/content/sqlitemanager.xul chrome://avim/content/avim.xul +# Edit Record dialog +overlay chrome://sqlitemanager/content/RowOperations.xul chrome://avim/content/avim.xul + +### Web Developer ############################################################## + +# Add Cookie dialog +overlay chrome://webdeveloper/content/dialogs/cookie.xul chrome://avim/content/avim.xul +# Add Tool dialog +overlay chrome://webdeveloper/content/options/dialogs/tool.xul chrome://avim/content/avim.xul +# Add View Source With dialog +overlay chrome://webdeveloper/content/options/dialogs/view_source_with.xul chrome://avim/content/avim.xul diff --git a/config_build.sh b/config_build.sh new file mode 100644 index 0000000..f8d640f --- /dev/null +++ b/config_build.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Build config for build.sh +APP_NAME=avim +CHROME_PROVIDERS="content locale skin" +CLEAN_UP=1 +ROOT_FILES="CHANGELOG LICENSE" +ROOT_DIRS="defaults" +VAR_FILES="install.rdf CHANGELOG LICENSE" +VERSION="20080224.$REV_NUM" +#"*CVS*" +PRUNE_DIRS="*.svn*" +BEFORE_BUILD= +AFTER_BUILD= diff --git a/content/avim.js b/content/avim.js new file mode 100755 index 0000000..9d4611f --- /dev/null +++ b/content/avim.js @@ -0,0 +1,1156 @@ +/** + * Default preferences. Be sure to update defaults/preferences/avim.js to + * reflect any changes to the default preferences. + */ +var AVIMConfig = { + method: 0, //Default input method: 0=AUTO, 1=TELEX, 2=VNI, 3=VIQR, 4=VIQR* + onOff: 1, //Starting status: 0=Off, 1=On + ckSpell: 1, //Spell Check: 0=Off, 1=On + oldAccent: 1, //0: New way (oa`, oe`, uy`), 1: The good old day (o`a, o`e, u`y) + informal: false, + statusBarPanel: true, // Display status bar panel + //IDs of the fields you DON'T want to let users type Vietnamese in + exclude: ["colorzilla-textbox-hex", // Hex box, Color Picker, ColorZilla + "email", "e-mail", // don't want it for e-mail fields in general + "textboxeval", // Code bar, Firefox Error Console + "tx_tagname", // Tag Name, Insert Node, DOM Inspector + ], + // Default input methods to contribute to Auto. + autoMethods: {telex: true, vni: true, viqr: false, viqrStar: false}, + // Script monitor + disabledScripts: { + enabled: true, + AVIM: true, CHIM: false, Mudim: false, + mViet: true, VietIMEW: false, VietTyping: true, VietUni: true + } +}; + +function AVIM() { + // IDs of user interface elements + this.commands = { + method: "avim-method-cmd", + prevMethod: "avim-prev-method-cmd", + nextMethod: "avim-next-method-cmd", + spell: "avim-spell-cmd", + oldAccents: "avim-oldaccents-cmd" + }; + this.broadcasters = { + enabled: "avim-enabled-bc", + methods: ["avim-auto-bc", "avim-telex-bc", "avim-vni-bc", + "avim-viqr-bc", "avim-viqr-star-bc"], + spell: "avim-spell-bc", + oldAccents: "avim-oldaccents-bc" + }; + this.keys = { + enabled: "avim-enabled-key", + prevMethod: "avim-prev-method-key", + nextMethod: "avim-next-method-key", + spell: "avim-spell-key", + oldAccents: "avim-oldaccents-key" + } +// this.menuItems = { +// methods: ["avim-menu-auto", "avim-menu-telex", "avim-menu-vni", +// "avim-menu-viqr", "avim-menu-viqr-star"] +// } + this.panel = "avim-status"; + + this.changed=false + this.alphabet="QWERTYUIOPASDFGHJKLZXCVBNM\ ";this.specialChange=false + this.skey=new Array(97,226,259,101,234,105,111,244,417,117,432,121,65,194,258,69,202,73,79,212,416,85,431,89) + this.range=null;this.whit=false;this.db1=new Array(273,272);this.ds1="d,D".split(",") + this.os1="o,O,ơ,Ơ,ó,Ó,ò,Ò,ọ,Ọ,ỏ,Ỏ,õ,Õ,ớ,Ớ,ờ,Ờ,ợ,Ợ,ở,Ở,ỡ,Ỡ".split(",");this.ob1="ô,Ô,ô,Ô,ố,Ố,ồ,Ồ,ộ,Ộ,ổ,Ổ,ỗ,Ỗ,ố,Ố,ồ,Ồ,ộ,Ộ,ổ,Ổ,ỗ,Ỗ".split(",") + this.mocs1="o,O,ô,Ô,u,U,ó,Ó,ò,Ò,ọ,Ọ,ỏ,Ỏ,õ,Õ,ú,Ú,ù,Ù,ụ,Ụ,ủ,Ủ,ũ,Ũ,ố,Ố,ồ,Ồ,ộ,Ộ,ổ,Ổ,ỗ,Ỗ".split(",");this.mocb1="ơ,Ơ,ơ,Ơ,ư,Ư,ớ,Ớ,ờ,Ờ,ợ,Ợ,ở,Ở,ỡ,Ỡ,ứ,Ứ,ừ,Ừ,ự,Ự,ử,Ử,ữ,Ữ,ớ,Ớ,ờ,Ờ,ợ,Ợ,ở,Ở,ỡ,Ỡ".split(",") + this.trangs1="a,A,â,Â,á,Á,à,À,ạ,Ạ,ả,Ả,ã,Ã,ấ,Ấ,ầ,Ầ,ậ,Ậ,ẩ,Ẩ,ẫ,Ẫ".split(",");this.trangb1="ă,Ă,ă,Ă,ắ,Ắ,ằ,Ằ,ặ,Ặ,ẳ,Ẳ,ẵ,Ẵ,ắ,Ắ,ằ,Ằ,ặ,Ặ,ẳ,Ẳ,ẵ,Ẵ".split(",") + this.as1="a,A,ă,Ă,á,Á,à,À,ạ,Ạ,ả,Ả,ã,Ã,ắ,Ắ,ằ,Ằ,ặ,Ặ,ẳ,Ẳ,ẵ,Ẵ,ế,Ế,ề,Ề,ệ,Ệ,ể,Ể,ễ,Ễ".split(",");this.ab1="â,Â,â,Â,ấ,Ấ,ầ,Ầ,ậ,Ậ,ẩ,Ẩ,ẫ,Ẫ,ấ,Ấ,ầ,Ầ,ậ,Ậ,ẩ,Ẩ,ẫ,Ẫ,é,É,è,È,ẹ,Ẹ,ẻ,Ẻ,ẽ,Ẽ".split(",") + this.es1="e,E,é,É,è,È,ẹ,Ẹ,ẻ,Ẻ,ẽ,Ẽ".split(",");this.eb1="ê,Ê,ế,Ế,ề,Ề,ệ,Ệ,ể,Ể,ễ,Ễ".split(",");this.english="ĐÂĂƠƯÊÔ" + this.lowen="đâăơưêô";this.arA="á,à,ả,ã,ạ,a,Á,À,Ả,Ã,Ạ,A".split(',');this.mocrA="ó,ò,ỏ,õ,ọ,o,ú,ù,ủ,ũ,ụ,u,Ó,Ò,Ỏ,Õ,Ọ,O,Ú,Ù,Ủ,Ũ,Ụ,U".split(',');this.erA="é,è,ẻ,ẽ,ẹ,e,É,È,Ẻ,Ẽ,Ẹ,E".split(',') + this.orA="ó,ò,ỏ,õ,ọ,o,Ó,Ò,Ỏ,Õ,Ọ,O".split(',');this.aA="ấ,ầ,ẩ,ẫ,ậ,â,Ấ,Ầ,Ẩ,Ẫ,Ậ,Â".split(',');this.oA="ố,ồ,ổ,ỗ,ộ,ô,Ố,Ồ,Ổ,Ỗ,Ộ,Ô".split(',') + this.mocA="ớ,ờ,ở,ỡ,ợ,ơ,ứ,ừ,ử,ữ,ự,ư,Ớ,Ờ,Ở,Ỡ,Ợ,Ơ,Ứ,Ừ,Ử,Ữ,Ự,Ư".split(',');this.trangA="ắ,ằ,ẳ,ẵ,ặ,ă,Ắ,Ằ,Ẳ,Ẵ,Ặ,Ă".split(',') + this.eA="ế,ề,ể,ễ,ệ,ê,Ế,Ề,Ể,Ễ,Ệ,Ê".split(',');this.oA="ố,ồ,ổ,ỗ,ộ,ô,Ố,Ồ,Ổ,Ỗ,Ộ,Ô".split(',');this.skey2="a,a,a,e,e,i,o,o,o,u,u,y,A,A,A,E,E,I,O,O,O,U,U,Y".split(',') + var fcc = String.fromCharCode; + var $ = function (id) { + return document.getElementById(id); + }; + this.getSF=function() { var sf=new Array(),x; for(x=0;x=0) for(a=0;a= 0) return true; + } + else if (uw.indexOf("F") >= 0 || uw.indexOf("Z") >= 0) return true; + for(a=0;a=0) next=false + if((next)&&((gi.indexOf(notViet[b])<0)||(a<=0)||(uw2.substr(a-1,1)!='G'))) return true + } + } + } + for(b=0;b=0) return true } + } + test=tw.substr(0,1) + if((t==3)&&((test=="A")||(test=="O")||(test=="U")||(test=="Y"))) return true + if((t==5)&&((test=="E")||(test=="I")||(test=="Y"))) return true + uw2=this.unV2(tw) + if(uw2==notV2) return true + if(tw!=twE) for(z=0;z0)&&(uk=='E')) check=false + if((this.them.indexOf(uk)>=0)&&(check)) { + for(a=0;a=0) return true + if(uk!=this.trang) if(uw2==noAOE) return true + if((uk==this.trang)&&(this.trang!='W')) if(uw2==noT) return true + if(uk==this.moc) for(a=0;a4) return true } + else if(uw2.length>3) return true + return false + } + + /** + * Enables or disables AVIM and updates the stored preferences. + * + * @param enabled {boolean} true to enable AVIM; false to disable it. + */ + this.setEnabled = function(enabled) { + AVIMConfig.onOff = 0 + enabled; + this.setPrefs(); + }; + + /** + * Enables AVIM if currently disabled; disables AVIM otherwise. + */ + this.toggle = function() { + this.setEnabled(!AVIMConfig.onOff); + }; + + /** + * Sets the input method to the method with the given ID and updates the + * stored preferences. If the given method ID is -1, the method is not + * changed and AVIM is instead disabled. + * + * @param m {number} the ID of the method to enable, or -1 to diable + * AVIM. + */ + this.setMethod=function(m) { + if (m == -1) AVIMConfig.onOff = 0; + else { + AVIMConfig.onOff = 1; + AVIMConfig.method = m; + } + this.setPrefs(); + }; + + /** + * Sets the input method to the one with the given distance away from the + * currently enabled input method. For instance, a distance of 1 selects the + * next input method, while a distance of -1 selects the previous one. + * + * @param distance {number} the distance from the currently selected input + * method to the input method to select. + */ + this.cycleMethod=function(distance) { + AVIMConfig.onOff = 1; + + var method = AVIMConfig.method; + method += distance; + if (method < 0) method += this.broadcasters.methods.length; + method %= this.broadcasters.methods.length; + AVIMConfig.method = method; + + this.setPrefs(); + }; + + /** + * Enables or disables old-style placement of diacritical marks over + * diphthongs and updates the stored preferences. + * + * @param enabled {boolean} true to use old-style diacritics; false to + * use new-style diacritics. + */ + this.setDauCu=function(enabled) { + AVIMConfig.oldAccent = 0 + enabled; + this.setPrefs() + } + + /** + * Enables old-style diacritical marks if currently disabled; disables them + * otherwise. + */ + this.toggleDauCu = function() { + this.setDauCu(!AVIMConfig.oldAccent); + }; + + /** + * Enables or disables spelling enforcement and updates the stored + * preferences. If enabled, diacritical marks are not placed over words that + * do not conform to Vietnamese spelling rules and are instead treated as + * literals. + * + * @param enabled {boolean} true to enforce spelling; false otherwise. + */ + this.setSpell=function(enabled) { + AVIMConfig.ckSpell = 0 + enabled; + this.setPrefs() + } + + /** + * Enables spelling enforcement if currently disabled; disables it + * otherwise. + */ + this.toggleSpell = function() { + this.setSpell(!AVIMConfig.ckSpell); + }; + + /** + * Displays or hides the status bar panel and updates the stored + * preferences. + * + * @param shown {boolean} true to display the status bar panel; false to + * hide it. + */ + this.setStatusPanel=function(shown) { + AVIMConfig.statusBarPanel = shown; + this.setPrefs() + } + + /** + * Displays the status bar panel if currently hidden; hides it otherwise. + */ + this.toggleStatusPanel = function() { + this.setStatusPanel(!AVIMConfig.statusBarPanel); + }; + + /** + * Updates the XUL menus and status bar panel to reflect AVIM's current + * state. + */ + this.updateUI = function() { + // Enabled/disabled + var bc_enabled = $(this.broadcasters.enabled); + if (bc_enabled) { + bc_enabled.setAttribute("checked", "" + !!AVIMConfig.onOff); + } + + // Disable methods and options if AVIM is disabled + for each (var cmd in this.commands) { + $(cmd).setAttribute("disabled", "" + !AVIMConfig.onOff); + } + + // Method + for each (var bc in this.broadcasters.methods) { + $(bc).removeAttribute("checked"); + $(bc).removeAttribute("key"); + } + var bc_sel = $(this.broadcasters.methods[AVIMConfig.method]); + if (bc_sel) bc_sel.setAttribute("checked", "true"); + +// var prev_bc_idx = AVIMConfig.method - 1; +// if (prev_bc_idx < 0) prev_bc_idx += this.menuItems.methods.length; +// var prev_bc = $(this.menuItems.methods[prev_bc_idx]); +// if (prev_bc) prev_bc.setAttribute("key", this.keys.prevMethod); +// +// var next_bc_idx = +// (AVIMConfig.method + 1) % this.menuItems.methods.length; +// var next_bc = $(this.menuItems.methods[next_bc_idx]); +// if (next_bc) next_bc.setAttribute("key", this.keys.nextMethod); + + // Options + var bc_spell = $(this.broadcasters.spell); + if (bc_spell) { + bc_spell.setAttribute("checked", "" + !!AVIMConfig.ckSpell); + } + var bc_old = $(this.broadcasters.oldAccents); + if (bc_old) { + bc_old.setAttribute("checked", "" + !!AVIMConfig.oldAccent); + } + + // Status bar panel + var panel = $(this.panel); + if (!panel) return; + if (AVIMConfig.onOff) { + panel.setAttribute("label", bc_sel.getAttribute("label")); + } + else panel.setAttribute("label", panel.getAttribute("disabledLabel")); + panel.style.display = + AVIMConfig.statusBarPanel ? "-moz-box" : "none"; +// var bc_panel = $(this.broadcasters.statusBarPanel); +// bc_panel.setAttribute("checked", "" + AVIMConfig.statusBarPanel); + }; + this.mozGetText=function(obj) { + var v,pos,w="",g=1 + v=(obj.data)?obj.data:obj.value + if(v.length<=0) return false + if(!obj.data) { + if(!obj.setSelectionRange) return false + pos=obj.selectionStart + } else pos=obj.pos + if(obj.selectionStart!=obj.selectionEnd) return new Array("",pos) + while(1) { + if(pos-g<0) break + else if(this.notWord(v.substr(pos-g,1))) { if(v.substr(pos-g,1)=="\\") w=v.substr(pos-g,1)+w; break } + else w=v.substr(pos-g,1)+w; g++ + } + return new Array(w,pos) + } + this.start=function(obj,key) { + var w="",method=AVIMConfig.method,dockspell=AVIMConfig.ckSpell,fixed=false,uni,uni2=false,uni3=false,uni4=false;this.oc=obj + var telex="D,A,E,O,W,W".split(','),vni="9,6,6,6,7,8".split(','),viqr="D,^,^,^,+,(".split(','),viqr2="D,^,^,^,*,(".split(','),a,noNormC + if(method==0) { + var arr=new Array(),check=new Array(AVIMConfig.autoMethods.telex,AVIMConfig.autoMethods.vni,AVIMConfig.autoMethods.viqr,AVIMConfig.autoMethods.viqrStar) + var value1=new Array(telex,vni,viqr,viqr2),uniA=new Array(uni,uni2,uni3,uni4),D2A=new Array("DAWEO","6789","D^+(","D^*(") + for(a=0;a=0) noNormC=true + else noNormC=false + this.main(w[0],key,w[1],uni,noNormC) + if(!dockspell) w=this.mozGetText(obj) + if((w)&&(uni2)&&(!this.changed)) this.main(w[0],key,w[1],uni2,noNormC) + if(!dockspell) w=this.mozGetText(obj) + if((w)&&(uni3)&&(!this.changed)) this.main(w[0],key,w[1],uni3,noNormC) + if(!dockspell) w=this.mozGetText(obj) + if((w)&&(uni4)&&(!this.changed)) this.main(w[0],key,w[1],uni4,noNormC) + if(this.D2.indexOf(this.up(key))>=0) { + w=this.mozGetText(obj) + if(!w) return + this.normC(w[0],key,w[1]) + } + } + this.findC=function(w,k,sf) { + var method=AVIMConfig.method + if(((method==3)||(method==4))&&(w.substr(w.length-1,1)=="\\")) return new Array(1,k.charCodeAt(0)) + var str="",res,cc="",pc="",tE="",vowA=new Array(),s="ÂĂÊÔƠƯêâăơôư",c=0,dn=false,uw=this.up(w),tv,g + var DAWEOFA=this.up(this.aA.join()+this.eA.join()+this.mocA.join()+this.trangA.join()+this.oA.join()+this.english),h,uc + for(g=0;g=0) { + if(uk==this.moc) { + if((w2.indexOf("UU")>=0)&&(this.tw5!=dont[1])) { + if(w2.indexOf("UU")==(w.length-2)) res=2 + else return false + } else if(w2.indexOf("UOU")>=0) { + if(w2.indexOf("UOU")==(w.length-3)) res=2 + else return false + } + } + if(!res) { + for(g=1;g<=w.length;g++) { + cc=w.substr(w.length-g,1) + pc=this.up(w.substr(w.length-g-1,1)) + uc=this.up(cc) + for(h=0;h=0) { + if(((uk==this.moc)&&(this.unV(uc)=="U")&&(this.up(this.unV(w.substr(w.length-g+1,1)))=="A"))||((uk==this.trang)&&(this.unV(uc)=='A')&&(this.unV(pc)=='U'))) { + if(this.unV(uc)=="U") tv=1 + else tv=2 + ccc=this.up(w.substr(w.length-g-tv,1)) + if(ccc!="Q") res=g+tv-1 + else if(uk==this.trang) res=g + else if(this.moc!=this.trang) return false + } else res=g + if((!this.whit)||(uw.indexOf("Ư")<0)||(uw.indexOf("W")<0)) break + } else if(DAWEOFA.indexOf(uc)>=0) { + if(uk==this.D) { + if(cc=="đ") res=new Array(g,'d') + else if(cc=="Đ") res=new Array(g,'D') + } else res=this.DAWEOF(cc,uk,g) + if(res) break + } + } + } + } + if((uk!=this.Z)&&(this.DAWEO.indexOf(uk)<0)) { var tEC=this.retKC(uk); for (g=0;g=0) { + if(cc=='U') { + if(pc!='Q') { c++;vowA[vowA.length]=g } + } else if(cc=='I') { + if((pc!='G')||(c<=0)) { c++;vowA[vowA.length]=g } + } else { c++;vowA[vowA.length]=g } + } else if(uk!=this.Z) { + for(h=0;h=0)) return g + else if(tE.indexOf(w.substr(w.length-g,1))>=0) { + for(h=0;h=0) { + c2++;fdconsonant=true + if(dc[g]!='NGH') h++ + else h+=2 + } + } + if(!fdconsonant) { + if(sc.indexOf(this.up(w.substr(w.length-h,1)))>=0) c2++ + else break + } + } + if((c2==1)||(c2==2)) return vowA[0] + else return vowA[1] + } else if(c==3) return vowA[1] + else return false + } + this.ie_replaceChar=function(w,pos,c) { + var r="",uc=0 + if(isNaN(c)) uc=this.up(c) + if((this.whit)&&(this.up(w.substr(w.length-pos-1,1))=='U')&&(pos!=1)&&(this.up(w.substr(w.length-pos-2,1))!='Q')) { + this.whit=false + if((this.up(this.unV(fcc(c)))=="Ơ")||(uc=="O")) { + if(w.substr(w.length-pos-1,1)=='u') r=fcc(432) + else r=fcc(431) + } + if(uc=="O") { + if(c=="o") c=417 + else c=416 + } + } + if(!isNaN(c)) { + this.changed=true;r+=fcc(c) + return w.substr(0,w.length-pos-r.length+1)+r+w.substr(w.length-pos+1) + } else return w.substr(0,w.length-pos)+c+w.substr(w.length-pos+1) + } + this.replaceChar=function(o,pos,c) { + var bb=false + if(!this.nan(c)) { var replaceBy=fcc(c),wfix=this.up(this.unV(fcc(c))); this.changed=true } + else { var replaceBy=c; if((this.up(c)=="O")&&(this.whit)) bb=true } + if(!o.data) { + var savePos=o.selectionStart,sst=o.scrollTop + if ((this.up(o.value.substr(pos-1,1))=='U')&&(pos=0) { + var ret=this.sr(w,k,i);got=true + if(ret) return ret + } else if(uk==this.Z) { + sf=this.repSign(null) + for(h=0;h=0)||(this.Z.indexOf(uk)>=0)) return this.tr(k,w,by,sf,i); return false; } + this.normC=function(w,k,i) { + var uk=this.up(k),u=this.repSign(null),fS,c,j,h,space=(k.charCodeAt(0)==32); + if(space) return ""; + for(j=1;j<=w.length;j++) { + for(h=0;h=0) + } + this.nan=function(w) { + return ((isNaN(w))||(w=='e')); + } + this.up=function(w) { + w=w.toUpperCase() + return w + } + this.findIgnore=function(el) { + return el.id && + AVIMConfig.exclude.indexOf(el.id.toLowerCase()) >= 0; + } + + /** + * Handles key presses in the current window. This function is triggered as + * soon as the key goes up. If the key press's target is a XUL element, this + * function finds the anonymous XBL child that actually handles text input, + * as necessary. + * + * @param e {object} the key press event. + * @returns {boolean} true if AVIM plans to modify the input; false + * otherwise. + */ + this.keyPressHandler=function(e) { + var el=e.target,code=e.which; +// dump("keyPressHandler -- target: " + el.tagName + "; code: " + code + "\n"); // debug + if(e.ctrlKey || e.metaKey) return false; + if(e.altKey) return false; + var xulURI = + "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + if (document.documentElement.namespaceURI == xulURI) { + // Ignore XUL pages embedded inside XUL windows. + if (document.documentElement.localName == "page") return false; + // Ignore about:config. + if (el.parentNode && el.parentNode.id == "filterRow") return false; + } + // If the XUL element is actually an XBL-bound element, get the + // anonymous inner element. This would be much easier if el.inputField + // actually worked. + if (el.namespaceURI == xulURI) { + var xulAnonIDs = { + searchbar: "searchbar-textbox", findbar: "findbar-textbox", + menulist: "input" + }; + if (xulAnonIDs[el.localName]) { + el = document.getAnonymousElementByAttribute(el, "anonid", + xulAnonIDs[el.localName]); + } + // TODO: Make this work in editable trees. +// var xulAnonClasses = { +// tree: "tree-input" +// }; +// if (xulAnonClasses[el.localName]) { +// var className = xulAnonClasses[el.localName]; +// var anons = document.getAnonymousElementByAttribute(el, "class", +// className); +// el = anons[0]; +// } +// if (el.localName == "tree") { +// el = document.getAnonymousElementByAttribute(stack, "anonid", +// "input"); +// } + } + var isHTML = el.type == "textarea" || el.type == "text"; + var xulTags = ["textbox", "searchbar", "findbar"]; + var isXUL = el.namespaceURI == xulURI && + xulTags.indexOf(el.localName) >= 0 && el.type != "password"; + if((!isHTML && !isXUL) || this.checkCode(code)) return false; + this.sk=fcc(code); if(this.findIgnore(el)) return false; + this.start(el,e) + if (this.changed) { + this.changed=false; + e.preventDefault(); + return false; + } + return true + } + this.attachEvt=function(obj,evt,handle,capture) { + obj.addEventListener(evt,handle,capture) + } + + // Integration with Mozilla preferences service + + // Root for AVIM preferences + this.prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefService) + .getBranch("extensions.avim."); + + /** + * Registers an observer so that AVIM automatically reflects changes to its + * preferences. + */ + this.registerPrefs = function() { + this.prefs.QueryInterface(Components.interfaces.nsIPrefBranch2); + this.prefs.addObserver("", this, false); + this.getPrefs(); + this.updateUI(); + }; + + /** + * Unregisters the preferences observer as the window is being closed. + */ + this.unregisterPrefs = function() { + this.setPrefs(); + this.prefs.removeObserver("", this); + }; + + /** + * Responds to changes to AVIM preferences. + * + * @param subject + * @param topic {string} the type of event that occurred. + * @param data {string} the name of the preference that changed. + */ + this.observe = function(subject, topic, data) { + if (topic != "nsPref:changed") return; + this.getPrefs(data); + this.updateUI(); + }; + + /** + * Updates the stored preferences to reflect AVIM's current state. + */ + this.setPrefs = function() { + // Basic options + this.prefs.setBoolPref("enabled", !!AVIMConfig.onOff); + this.prefs.setIntPref("method", AVIMConfig.method); + this.prefs.setBoolPref("ignoreMalformed", !!AVIMConfig.ckSpell); + this.prefs.setBoolPref("oldAccents", !!AVIMConfig.oldAccent); + this.prefs.setBoolPref("statusBarPanel", + AVIMConfig.statusBarPanel); + + // Advanced options + this.prefs.setBoolPref("informal", !!AVIMConfig.informal); + var ids = AVIMConfig.exclude.join(" ").toLowerCase(); + this.prefs.setCharPref("ignoredFieldIds", ids); + + // Auto input method configuration + this.prefs.setBoolPref("auto.telex", + AVIMConfig.autoMethods.telex); + this.prefs.setBoolPref("auto.vni", AVIMConfig.autoMethods.vni); + this.prefs.setBoolPref("auto.viqr", AVIMConfig.autoMethods.viqr); + this.prefs.setBoolPref("auto.viqrStar", + AVIMConfig.autoMethods.viqrStar); + + // Script monitor + this.prefs.setBoolPref("scriptMonitor.enabled", + AVIMConfig.disabledScripts.enabled); + this.prefs.setBoolPref("scriptMonitor.avim", + AVIMConfig.disabledScripts.AVIM); + this.prefs.setBoolPref("scriptMonitor.chim", + AVIMConfig.disabledScripts.CHIM); + this.prefs.setBoolPref("scriptMonitor.mudim", + AVIMConfig.disabledScripts.Mudim); + this.prefs.setBoolPref("scriptMonitor.mViet", + AVIMConfig.disabledScripts.mViet); + this.prefs.setBoolPref("scriptMonitor.vietImeW", + AVIMConfig.disabledScripts.VietIMEW); + this.prefs.setBoolPref("scriptMonitor.vietTyping", + AVIMConfig.disabledScripts.VietTyping); + this.prefs.setBoolPref("scriptMonitor.vietUni", + AVIMConfig.disabledScripts.VietUni); + }; + + /** + * Updates AVIM's current state to reflect the stored preferences. + * + * @param changedPref {string} the name of the preference that changed. + */ + this.getPrefs = function(changedPref) { +// dump("Changed pref: " + changedPref + "\n"); // debug + var specificPref = true; + switch (changedPref) { + default: + // Fall through when changedPref isn't defined, which happens at + // startup, when we want to get all the preferences. + specificPref = false; + + // Basic options + case "enabled": + AVIMConfig.onOff = 0 + this.prefs.getBoolPref("enabled"); + if (specificPref) break; + case "method": + AVIMConfig.method = this.prefs.getIntPref("method"); + // In case someone enters an invalid method ID in about:config + var method = AVIMConfig.method; + if (method < 0 || method >= this.broadcasters.methods.length) { + Components.classes["@mozilla.org/preferences-service;1"] + .getService(Components.interfaces.nsIPrefService) + .getDefaultBranch("extensions.avim.") + .clearUserPref("method"); + AVIMConfig.method = this.prefs.getIntPref("method"); + } + if (specificPref) break; + case "ignoreMalformed": + AVIMConfig.ckSpell = + 0 + this.prefs.getBoolPref("ignoreMalformed"); + if (specificPref) break; + case "oldAccents": + AVIMConfig.oldAccent = 0 + this.prefs.getBoolPref("oldAccents"); + if (specificPref) break; + case "statusBarPanel": + AVIMConfig.statusBarPanel = + this.prefs.getBoolPref("statusBarPanel"); + if (specificPref) break; + + // Advanced options + case "informal": + AVIMConfig.informal = this.prefs.getBoolPref("informal"); + if (specificPref) break; + case "ignoredFieldIds": + var ids = this.prefs.getCharPref("ignoredFieldIds"); + AVIMConfig.exclude = ids.toLowerCase().split(/\s+/); + if (specificPref) break; + + // Auto input method configuration + case "auto.telex": + AVIMConfig.autoMethods.telex = + this.prefs.getBoolPref("auto.telex"); + if (specificPref) break; + case "auto.vni": + AVIMConfig.autoMethods.vni = this.prefs.getBoolPref("auto.vni"); + if (specificPref) break; + case "auto.viqr": + AVIMConfig.autoMethods.viqr = + this.prefs.getBoolPref("auto.viqr"); + if (specificPref) break; + case "auto.viqrStar": + AVIMConfig.autoMethods.viqrStar = + this.prefs.getBoolPref("auto.viqrStar"); + if (specificPref) break; + + // Script monitor + case "scriptMonitor.enabled": + AVIMConfig.disabledScripts.enabled = + this.prefs.getBoolPref("scriptMonitor.enabled"); + if (specificPref) break; + case "scriptMonitor.avim": + AVIMConfig.disabledScripts.AVIM = + this.prefs.getBoolPref("scriptMonitor.avim"); + if (specificPref) break; + case "scriptMonitor.chim": + AVIMConfig.disabledScripts.CHIM = + this.prefs.getBoolPref("scriptMonitor.chim"); + if (specificPref) break; + case "scriptMonitor.mudim": + AVIMConfig.disabledScripts.Mudim = + this.prefs.getBoolPref("scriptMonitor.mudim"); + if (specificPref) break; + case "scriptMonitor.mViet": + AVIMConfig.disabledScripts.mViet = + this.prefs.getBoolPref("scriptMonitor.mViet"); + if (specificPref) break; + case "scriptMonitor.vietImeW": + AVIMConfig.disabledScripts.VietIMEW = + this.prefs.getBoolPref("scriptMonitor.vietImeW"); + if (specificPref) break; + case "scriptMonitor.vietTyping": + AVIMConfig.disabledScripts.VietTyping = + this.prefs.getBoolPref("scriptMonitor.vietTyping"); + if (specificPref) break; + case "scriptMonitor.vietUni": + AVIMConfig.disabledScripts.VietUni = + this.prefs.getBoolPref("scriptMonitor.vietUni"); +// if (specificPref) break; + } + }; + + // Script monitor + + // Markers and disablers for embedded Vietnamese IMEs + var disablers = { + // For each of these disablers, we don't need a sanity check for an + // object or member that served as a marker for the IME. Also, + // everything is wrapped in a try...cach block, so we don't need sanity + // checks if the disabler can halt on error without failing to reach + // independent statements. + + AVIM: function(win, AVIMObj) { + if (!AVIMConfig.disabledScripts.AVIM) return; + AVIMObj.setMethod(-1); + }, + CHIM: function(win, CHIM) { + if (!AVIMConfig.disabledScripts.CHIM) return; + if (parseInt(CHIM.method) == 0) return; + CHIM.SetMethod(0); + }, + HIM: function(win) { + if (!AVIMConfig.disabledScripts.AVIM) return; + if ("setMethod" in win) win.setMethod(-1); + win.on_off = 0; + }, + Mudim: function(win, Mudim) { + if (!AVIMConfig.disabledScripts.Mudim) return; + if (parseInt(Mudim.method) == 0) return; + if ("Toggle" in Mudim) Mudim.Toggle(); + else win.CHIM.Toggle(); + }, + mViet: function(win) { + if (!AVIMConfig.disabledScripts.mViet) return; + if (typeof(win.MVOff) == "boolean" && win.MVOff) return; + if ("MVietOnOffButton" in win) win.MVietOnOffButton(); + else if ("button" in win) win.button(0); + }, + VietIMEW: function(win) { + if (!AVIMConfig.disabledScripts.VietIMEW) return; + if (!("VietIME" in win)) return; + for (var memName in win) { + var mem = win[memName]; + if (mem.setTelexMode != undefined && + mem.setNormalMode != undefined) { + mem.setNormalMode(); + break; + } + } + }, + VietTyping: function(win) { + if (!AVIMConfig.disabledScripts.VietTyping) return; + if ("changeMode" in win) win.changeMode(-1); + else win.ON_OFF = 0; + }, + VietUni: function(win) { + if (!AVIMConfig.disabledScripts.VietUni) return; + win.setTypingMode(); + }, + xvnkb: function(win) { + if (!AVIMConfig.disabledScripts.CHIM) return; + if (parseInt(win.vnMethod) == 0) return; + win.VKSetMethod(0); + } + }; + var markers = { + // HIM and AVIM since at least version 1.13 (build 20050810) + "DAWEOF": disablers.HIM, + // VietTyping, various versions + "UNIZZ": disablers.VietTyping, + // VietUni, including vietuni8.js (2001-10-19) and version 14.0 by Tran + // Kien Duc (2004-01-07) + "telexingVietUC": disablers.VietUni, + // Mudim since version 0.3 (r2) + "Mudim": disablers.Mudim, + // mViet 12 AC + "evBX": disablers.mViet, + // mViet 14 RTE + "MVietOnOffButton": disablers.mViet, + // CHIM since version 0.9.3 + "CHIM": disablers.CHIM, + // CHIM (xvnkb.js) versions 0.8-0.9.2 and BIM 0.00.01-0.0.3 + "vnMethod": disablers.xvnkb, + // HIM since at least version 1.1 (build 20050430) + "DAWEO": disablers.HIM, + // HIM since version 1.0 + "findCharToChange": disablers.HIM, + // AVIM after build 20071102 + "AVIMObj": disablers.AVIM, + // VietIMEW + "GetVnVowelIndex": disablers.VietIMEW + }; + + /** + * Given a context and marker, disables the Vietnamese JavaScript input + * method editor (IME) with that marker. + * + * @param win {object} A JavaScript window object. + * @param marker {object} A JavaScript object (possibly a function) + * that indicates the presence of the IME. + * @returns {boolean} True if the disabler ran without errors (possibly + * without effect); false if errors were raised. + */ + this.disableOther = function(win, marker) { + try { + var disabler = markers[marker]; + disabler(win, win[marker]); + return true; + } + catch (e) { + return false; + } + }; + + /** + * Given a HTML document node, disables any Vietnamese JavaScript input + * method editors (IMEs) embedded in the document that may cause conflicts. + * If AVIM is disabled, this method does nothing. + * + * @param doc {object} An HTML document node. + */ + this.disableOthers = function(doc) { + if (!AVIMConfig.onOff || !AVIMConfig.disabledScripts.enabled) return; + + // Using wrappedJSObject is only safe in Firefox 3 and above. + var winWrapper = new XPCNativeWrapper(doc.defaultView); + var win = winWrapper.wrappedJSObject; + if (!win || win == window) return; + + for (var marker in markers) { + if (!(marker in win)) continue; + if (this.disableOther(win, marker)) return; + } + + // mViet 14 RTE + if (!AVIMConfig.disabledScripts.mViet) return; + if (win.frameElement) win = win.frameElement.ownerDocument.defaultView; + var marker = "MVietOnOffButton"; + if (marker in win) disablers.mViet(win); + }; +} + +if (!AVIMObj) { + var AVIMObj=new AVIM() + addEventListener("load", function (e) { + AVIMObj.registerPrefs(); + }, false); + addEventListener("unload", function (e) { + AVIMObj.unregisterPrefs(); + }, false); + addEventListener("keypress", function (e) { +// dump("keyPressHandler -- code: " + e.which + "\n"); // debug +// dump("keyPressHandler -- target: " + e.target.nodeName + "\n"); // debug + var doc = e.target.ownerDocument; + AVIMObj.disableOthers(doc); + + // Handle key press either in WYSIWYG mode or normal mode. + var wysiwyg = + (doc.designMode && doc.designMode.toLowerCase() == "on") || + (e.target.contentEditable && + e.target.contentEditable.toLowerCase() == "true"); + if (wysiwyg) return AVIMObj.ifMoz(e); + + return AVIMObj.keyPressHandler(e); + }, true); +} diff --git a/content/avim.png b/content/avim.png new file mode 100644 index 0000000..038b1fb Binary files /dev/null and b/content/avim.png differ diff --git a/content/avim.xul b/content/avim.xul new file mode 100755 index 0000000..51e16f6 --- /dev/null +++ b/content/avim.xul @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +