/* Author: Muhammad Abdulla (muhammad@yulghun.com)
* Version: 1.2 (Feb. 7, 2009)
* License: GPL
*/
var imode = 0; // input mode, default is Uyghur
var qmode = 0; // quote mode, 0 for opening, 1 for closing
var km = new Array ( 128 ); // keymap
var cm = new Array ( 256 ); // charmap
var PRIMe = 233; // 'e
var PRIME = 201; // 'E
var COLo = 246; // :o
var COLO = 214; // :O
var COLu = 252; // :u
var COLU = 220; // :U
var HAMZA = 0x0626;
var CHEE = 0x0686;
var GHEE = 0x063A;
var NGEE = 0x06AD;
var SHEE = 0x0634;
var SZEE = 0x0698;
// right and left quotes in Uyghur
var OQUOTE = 0x00AB; // for opening quote (oh quote)
var CQUOTE = 0x00BB; // for closing quote
var RCQUOTE = 0x2019; // 0x2019 is right closed curly quote
var BPAD = 0x0600;
// returns a char code for a given character
function gac ( ascii )
{
var str = "" + ascii;
return str.charCodeAt(0);
}
// returns a string from a given char code
function gas ( code )
{
return String.fromCharCode(code);
}
var i;
var inited = false;
function bedit_init ( ) {
var i;
if ( inited ) {
return;
}
inited = true;
// zero-out all entries first
for ( i = 0; i < km.length; i++ ) {
km[i] = 0;
}
// Uyghur Unicode character map
km[gac('a')] = 0x06BE;
km[gac('b')] = 0x0628;
km[gac('c')] = 0x063A;
km[gac('D')] = 0x0698;
km[gac('d')] = 0x062F;
km[gac('e')] = 0x06D0;
km[gac('f')] = 0x0627;
km[gac('F')] = 0x0641;
km[gac('G')] = 0x06AF;
km[gac('g')] = 0x06D5;
km[gac('H')] = 0x062E;
km[gac('h')] = 0x0649;
km[gac('i')] = 0x06AD;
km[gac('J')] = 0x062C;
km[gac('j')] = 0x0642;
km[gac('K')] = 0x06C6;
km[gac('k')] = 0x0643;
km[gac('l')] = 0x0644;
km[gac('m')] = 0x0645;
km[gac('n')] = 0x0646;
km[gac('o')] = 0x0648;
km[gac('p')] = 0x067E;
km[gac('q')] = 0x0686;
km[gac('r')] = 0x0631;
km[gac('s')] = 0x0633;
km[gac('T')] = 0x0640; // space filler character
km[gac('t')] = 0x062A;
km[gac('u')] = 0x06C7;
km[gac('v')] = 0x06C8;
km[gac('w')] = 0x06CB;
km[gac('x')] = 0x0634;
km[gac('y')] = 0x064A;
km[gac('z')] = 0x0632;
km[gac('/')] = 0x0626;
for ( i = 0; i < km.length; i++ ) {
if ( km[i] != 0 ) {
var u = gac(gas(i).toUpperCase());
if ( km[u] == 0 ) {
km[u] = km[i];
}
}
}
// Uyghur punctuation marks
km[gac(';')] = 0x061B;
km[gac('?')] = 0x061F;
km[gac(',')] = 0x060C;
km[gac('<')] = 0x203A; // for '‹'
km[gac('>')] = 0x2039; // for '›'
km[gac('"')] = OQUOTE;
// adapt parens, brackets, and braces for right-to-left typing
km[gac('{')] = gac ( '}' );
km[gac('}')] = gac ( '{' );
km[gac('[')] = gac ( ']' );
km[gac(']')] = gac ( '[' );
km[gac('(')] = gac ( ')' );
km[gac(')')] = gac ( '(' );
// special handling of braces ( "{" and "}" ) for quotation in Uyghur
km[gac('}')] = 0x00AB;
km[gac('{')] = 0x00BB;
// zero-out all entries first
for ( i = 0; i < cm.length; i++ ) {
cm[i] = 0;
}
cm[gac('a')] = 0x0627;
cm[gac('b')] = 0x0628;
cm[gac('c')] = 0x0643;
cm[gac('d')] = 0x062F;
cm[gac('e')] = 0x06D5;
cm[gac('f')] = 0x0641;
cm[gac('g')] = 0x06AF;
cm[gac('h')] = 0x06BE;
cm[gac('i')] = 0x0649;
cm[gac('j')] = 0x062C;
cm[gac('k')] = 0x0643;
cm[gac('l')] = 0x0644;
cm[gac('m')] = 0x0645;
cm[gac('n')] = 0x0646;
cm[gac('o')] = 0x0648;
cm[gac('p')] = 0x067E;
cm[gac('q')] = 0x0642;
cm[gac('r')] = 0x0631;
cm[gac('s')] = 0x0633;
cm[gac('t')] = 0x062A;
cm[gac('u')] = 0x06C7;
cm[gac('v')] = 0x06CB;
cm[gac('w')] = 0x06CB;
cm[gac('x')] = 0x062E;
cm[gac('y')] = 0x064A;
cm[gac('z')] = 0x0632;
cm[PRIMe] = 0x06D0; // 'e
cm[PRIME] = 0x06D0; // 'E
cm[COLo] = 0x06C6; // :o
cm[COLO] = 0x06C6; // :O
cm[COLu] = 0x06C8; // :u
cm[COLU] = 0x06C8; // :U
for ( i = 0; i < cm.length; i++ ) {
if ( cm[i] != 0 ) {
var u = gac(gas(i).toUpperCase());
if ( cm[u] == 0 ) {
cm[u] = cm[i];
}
}
}
// Uyghur punctuation marks
cm[gac(';')] = 0x061B;
cm[gac('?')] = 0x061F;
cm[gac(',')] = 0x060C;
}
function ak2uni ( akstr )
{
var str = akstr;
var akdif = String.fromCharCode(0x0622, 0x0623, 0x0624, 0x0626, 0x0629, 0x062B, 0x062D, 0x0630, 0x0635, 0x0636, 0x0638, 0x0649, 0x0639, 0x0647, gac('{'), gac('}'));
var akuni = String.fromCharCode(0x0698, 0x06C6, 0x06CB, 0x06D0, 0x06D5, 0x06AD, 0x0686, 0x06C7, 0x067E, 0x06AF, 0x0626, 0x06C8, 0x0649, 0x06BE, CQUOTE, OQUOTE);
for(var i = 0; i < akdif.length; i++ ) {
str = str.replace(new RegExp(akdif.substr(i,1), "g"), akuni.substr(i,1));
}
return str;
}
function uly2uy ( ustr )
{
var str = "";
var i, cur, prev, next, ch;
var ccode, ncode;
var wdbeg = true;
var bd = '`'; // beginning delimiter
var ed = '`'; // ending delimiter
var verbatim = false;
var uly = ustr;
// make URLs verbatim
var regExp = /(\w+[p|s]:\/\/\S*)/gi;
uly = uly.replace(regExp, bd + "$1" + ed );
// URLs without ://
regExp = /([\s|(]+\w+\.\w+\.\w+\S*)/g;
uly = uly.replace(regExp, bd + "$1" + ed );
// two-part URLs with well-known suffixes
regExp = /([\s|(|,|.]+\w+\.(com|net|org|cn)[\s|)|\.|,|.|$])/g;
uly = uly.replace(regExp, bd + "$1" + ed );
// email addresses
regExp = /(\w+@\w+\.\w[\w|\.]*\w)/g;
uly = uly.replace(regExp, bd + "$1" + ed );
if ( !inited ) {
bedit_init();
}
for ( i = 0; i < uly.length; i++ ) {
ch = 0;
cur = uly.charAt(i);
next = uly.charAt(i+1);
ccode = uly.charCodeAt(i);
ncode = uly.charCodeAt(i+1);
if ( verbatim == true ) {
if ( cur == ed ) { // ending verbatim mode
verbatim = false;
} else {
str += cur;
}
continue;
}
if ( cur == bd ) {
verbatim = true;
continue;
}
if ( cur == '|' && ( prev == 'u' ) && ( next == 'a' || next == 'e' ) ) {
wdbeg = false;
continue;
}
// add hamza in front of vowels in word-beginning positions
if ( wdbeg == true ) {
if ( isvowel(cur) ) {
str += gas(HAMZA);
}
} else {
if ( cur == '\'' || ccode == RCQUOTE ) {
if ( isvowel(next) ) {
wdbeg = false; // don't add another hamza in next round
str += gas(HAMZA);
continue;
} else if ( isalpha(ncode) ) {
continue;
}
}
}
// AA, AE, and non-alpha-numeric letters makes word beginning
if ( isvowel(cur) || !isalpha(ccode) ) {
wdbeg = true;
} else {
wdbeg = false;
}
switch ( cur ) { // handle joint-letters
case 'c':
case 'C':
if ( next == 'h' || next == 'H' ) {
ch = CHEE;
}
break;
case 'g':
case 'G':
if ( next == 'h' || next == 'H' ) {
ch = GHEE;
}
break;
case 'n':
case 'N':
if ( next == 'g' || next == 'G' ) {
tmpch = uly.charAt(i+2);
if ( tmpch != 'h' && tmpch != 'H' ) {
ch = NGEE;
}
}
break;
case 's':
case 'S':
if ( next == 'h' || next == 'H' ) {
ch = SHEE;
} else if ( next == 'z' || next == 'Z' ) { // ULY does not provide a unique SZEE, we use 'sz'
ch = SZEE;
}
break;
default:
break;
}
if ( ch != 0 ) {
i++; // advance index for joint letters
str += gas(ch);
} else if ( ccode < cm.length && cm[ccode] ) {
str += gas( cm[ccode] ); // no joint letter, but valid ULY
} else {
str += gas(ccode); // non-ULY, return whatever is entered
}
prev = cur;
}
return str;
}
// isvowel -- returns true if ch is a vowel in Uyghur
function isvowel ( ch )
{
var code = gac ( ch );
if ( ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u' ||
ch == 'A' || ch == 'E' || ch == 'I' || ch == 'O' || ch == 'U' ) {
return true;
}
if ( code == PRIMe || code == PRIME || code == COLo ||
code == COLO || code == COLu || code == COLU ) {
return true;
}
return false;
}
function isalpha ( code )
{
if ( (gac('A') <= code && code <= gac('Z')) || (gac('a') <= code && code <= gac('z')) ) {
return true;
}
return false;
}
function AttachEvent(obj, evt, fnc, useCapture){
if (!useCapture) useCapture = false;
if (obj.addEventListener) {
obj.removeEventListener(evt, fnc, useCapture);
obj.addEventListener(evt, fnc, useCapture);
return true;
} else if (obj.attachEvent) {
obj.detachEvent( "on" + evt, fnc);
return obj.attachEvent( "on" + evt, fnc);
}
}
// attach event handlers to textareas and textfields
function attachEvents ( )
{
if ( typeof(attachAll)=="undefined" || attachAll == null ) {
attachAll = false;
}
if ( typeof(bedit_allow) != "undefined" && bedit_allow && bedit_allow.length != 0 ) {
allowed_names = bedit_allow.split ( ':' );
} else {
allowed_names = new Array();
}
if ( typeof(bedit_deny) != "undefined" && bedit_deny && bedit_deny.length != 0 ) {
denied_names = bedit_deny.split ( ':' );
} else {
denied_names = new Array();;
}
var tas = document.getElementsByTagName("TEXTAREA"); // textareas
var tfs = document.getElementsByTagName("INPUT"); // input fields
for ( i = 0; i < tas.length; i++ ) {
if ( shouldAttach(tas[i].name) ) {
AttachEvent ( tas[i], 'keypress', naddchar, false );
AttachEvent ( tas[i], 'keydown', proc_kd, false );
}
}
for ( i = 0; i < tfs.length; i++ ) {
if ( tfs[i].type.toLowerCase() == "text" && shouldAttach(tfs[i].name)) {
AttachEvent ( tfs[i], 'keypress', naddchar, false );
AttachEvent ( tfs[i], 'keydown', proc_kd, false );
}
}
}
function shouldAttach ( name )
{
var j;
if ( attachAll == true ) {
for ( j = 0; j < denied_names.length; j++ ) {
if ( name == denied_names[j] ) {
return false;
}
}
return true;
} else { // global attach is disabled, only attach those that are specified
for ( j = 0; j < allowed_names.length; j++ ) {
if ( name == allowed_names[j] ) {
return true;
}
}
return false;
}
}
/* for Mozilla/Opera (taken from dean.edwards.name) */
if (document.addEventListener) {
document.addEventListener("DOMContentLoaded", bedit_onLoad, false);
}
/* for Internet Explorer */
/*@cc_on @*/
/*@if (@_win32)
document.write("<script id=__ie_onload defer src=javascript:void(0)><\/script>");
var script = document.getElementById("__ie_onload");
script.onreadystatechange = function() {
if (this.readyState == "complete") {
bedit_onLoad(); // call the onload handler
}
};
/*@end @*/
/* for webkit-based browsers */
if (/WebKit/i.test(navigator.userAgent)) { // sniff
var _timer = setInterval(function() {
if (/loaded|complete/.test(document.readyState)) {
bedit_onLoad(); // call the onload handler
}
}, 100);
}
// add new onLoad while keeping the old, if any
old_onLoad = null;
add_onLoad();
function add_onLoad()
{
old_onLoad = window.onload;
window.onload = bedit_onLoad;
}
function bedit_onLoad()
{
// quit if this function has already been called
if (arguments.callee.done) return;
arguments.callee.done = true;
// kill the timer
if (_timer) clearInterval(_timer);
bedit_init();
attachEvents();
if ( old_onLoad ) {
old_onLoad();
}
}
function addchar(content, event)
{
return naddchar(event);
}
function proc_kd_ctrl_k ( source, ev )
{
imode = 1 - imode;
return true;
}
function proc_kd_ctrl_j ( source, ev )
{
var t = gsel(source);
if ( t == "" ) {
return false;
} else {
ins(source, ak2uni(t));
return true;
}
}
function proc_kd_ctrl_u ( source, ev )
{
var t = gsel(source);
if ( t == "" ) {
return false;
} else {
ins(source, uly2uy(t));
return true;
}
}
function proc_kd_ctrl_t ( source, ev )
{
if ( source.style.direction == "ltr" ) {
source.style.direction = "rtl";
} else {
source.style.direction = "ltr";
}
return true;
}
function proc_kd(event)
{
var x = false; // should cancel?
var e = event ? event : window.event;
var k = e.keyCode ? e.keyCode : e.which;
var s = e.srcElement ? e.srcElement : e.target;
if ( e.ctrlKey) {
var f = false;
for(var az = gac('A'); az <= gac('Z'); az++ ) {
eval('if ( k == ' + az + ' && typeof proc_kd_ctrl_' + gas(az).toLowerCase() + ' == "function" ) { x = ' + 'proc_kd_ctrl_' + gas(az).toLowerCase(az) + '(s, e); f=true;}');
if(f) break;
}
}
if ( x ) {
e.cancelBubble = true;
if(e.preventDefault) e.preventDefault();
if(e.stopPropagation) e.stopPropagation();
e.returnValue = false;
return false;
}
return true;
}
function gsel(source)
{
var s = source;
if ( document.all ) {
return document.selection.createRange().text;
} else {
var ss = s.selectionStart;
var se = s.selectionEnd;
if ( ss < se ) {
return s.value.substring (ss, se);
}
}
return "";
}
function ins(source, str)
{
var s = source;
if ( document.selection && document.selection.createRange) {
document.selection.createRange().text = str;
} else {
// we cannot modify event.which in Mozilla/FireFox, have to do something more interesting
var ss = s.selectionStart;
var se = s.selectionEnd;
// Mozilla/Firefox scrolls to top in textarea after text input, fix it:
var sTop, sLeft;
if (s.type == 'textarea' && typeof s.scrollTop != 'undefined') {
sTop = s.scrollTop;
sLeft = s.scrollLeft;
}
s.value = s.value.substring (0, ss) + str + s.value.substr(se);
if (typeof sTop != 'undefined') {
s.scrollTop = sTop;
s.scrollLeft = sLeft;
}
s.setSelectionRange(ss + str.length, ss + str.length );
}
}
// addchar
function naddchar(event)
{
var e = event ? event : window.event;
var k = e.keyCode ? e.keyCode : e.which;
var s = e.srcElement ? e.srcElement : e.target;
if ( !inited ) {
bedit_init();
}
if ( !e.ctrlKey && !e.metaKey && imode == 0 && k < km.length && km[k] != 0 ) {
if ( e.keyCode && !e.which ) {
e.keyCode = km[k];
} else {
ins(s, gas(km[k]));
if(e.preventDefault) e.preventDefault();
if(e.stopPropagation) e.stopPropagation();
}
if ( k == gac('"') ) { // toggle double bracket on '"'
km[k] = qmode ? OQUOTE : CQUOTE;
qmode = 1 - qmode;
}
if ( ! e.keyCode || e.which ) {
return false;
}
}
// cannot cancel keydown event in opera, do it in here for keypress
if (/opera/i.test(navigator.userAgent) && e.ctrlKey) {
var x = false;
for(var az = gac('A'); az <= gac('Z'); az++ ) {
eval('if(k == ' + az + ' && typeof proc_kd_ctrl_' + gas(az).toLowerCase() + ' == "function" ) { x = true }');
if(x) break;
}
if(x) {
e.preventDefault();
return false;
}
}
e.returnValue = true;
return true;
}