314 lines
8.8 KiB
JavaScript
314 lines
8.8 KiB
JavaScript
|
dojo.provide("dojox.string.BidiComplex");
|
||
|
dojo.experimental("dojox.string.BidiComplex");
|
||
|
|
||
|
// summary:
|
||
|
// BiDiComplex module handles complex expression issues known when using BiDi characters
|
||
|
// in File Paths, URLs, E-mail Address, XPATH, etc.
|
||
|
// this module adds property listeners to the text fields to correct the text representation
|
||
|
// in both static text and dynamic text during user input.
|
||
|
|
||
|
(function(){
|
||
|
|
||
|
var _str0 = []; //FIXME: shared reference here among various functions means the functions can't be reused
|
||
|
|
||
|
dojox.string.BidiComplex.attachInput = function(/*DOMNode*/field, /*String*/pattern){
|
||
|
// summary:
|
||
|
// Attach key listeners to the INPUT field to accomodate dynamic complex BiDi expressions
|
||
|
// field: INPUT DOM node
|
||
|
// pattern: Complex Expression Pattern type. One of "FILE_PATH", "URL", "EMAIL", "XPATH"
|
||
|
|
||
|
field.alt = pattern;
|
||
|
|
||
|
dojo.connect(field, "onkeydown", this, "_ceKeyDown");
|
||
|
dojo.connect(field, "onkeyup", this, "_ceKeyUp");
|
||
|
|
||
|
dojo.connect(field, "oncut", this, "_ceCutText");
|
||
|
dojo.connect(field, "oncopy", this, "_ceCopyText");
|
||
|
|
||
|
field.value = dojox.string.BidiComplex.createDisplayString(field.value, field.alt);
|
||
|
};
|
||
|
|
||
|
dojox.string.BidiComplex.createDisplayString = function(/*String*/str, /*String*/pattern){
|
||
|
// summary:
|
||
|
// Create the display string by adding the Unicode direction Markers
|
||
|
// pattern: Complex Expression Pattern type. One of "FILE_PATH", "URL", "EMAIL", "XPATH"
|
||
|
|
||
|
str = dojox.string.BidiComplex.stripSpecialCharacters(str);
|
||
|
var segmentsPointers = dojox.string.BidiComplex._parse(str, pattern);
|
||
|
|
||
|
var buf = '\u202A'/*LRE*/ + str;
|
||
|
var shift = 1;
|
||
|
dojo.forEach(segmentsPointers, function(n){
|
||
|
if(n != null){
|
||
|
var preStr = buf.substring(0, n + shift);
|
||
|
var postStr = buf.substring(n + shift, buf.length);
|
||
|
buf = preStr + '\u200E'/*LRM*/ + postStr;
|
||
|
shift++;
|
||
|
}
|
||
|
});
|
||
|
return buf;
|
||
|
};
|
||
|
|
||
|
dojox.string.BidiComplex.stripSpecialCharacters = function(str){
|
||
|
// summary:
|
||
|
// removes all Unicode directional markers from the string
|
||
|
|
||
|
return str.replace(/[\u200E\u200F\u202A-\u202E]/g, ""); // String
|
||
|
};
|
||
|
|
||
|
dojox.string.BidiComplex._ceKeyDown = function(event){
|
||
|
var elem = dojo.isIE ? event.srcElement : event.target;
|
||
|
_str0 = elem.value;
|
||
|
};
|
||
|
|
||
|
dojox.string.BidiComplex._ceKeyUp = function(event){
|
||
|
var LRM = '\u200E';
|
||
|
var elem = dojo.isIE ? event.srcElement : event.target;
|
||
|
|
||
|
var str1 = elem.value;
|
||
|
var ieKey = event.keyCode;
|
||
|
|
||
|
if((ieKey == dojo.keys.HOME)
|
||
|
|| (ieKey == dojo.keys.END)
|
||
|
|| (ieKey == dojo.keys.SHIFT)){
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var cursorStart, cursorEnd;
|
||
|
var selection = dojox.string.BidiComplex._getCaretPos(event, elem);
|
||
|
if(selection){
|
||
|
cursorStart = selection[0];
|
||
|
cursorEnd = selection[1];
|
||
|
}
|
||
|
|
||
|
//Jump over a cursor processing
|
||
|
if(dojo.isIE){
|
||
|
var cursorStart1 = cursorStart, cursorEnd1 = cursorEnd;
|
||
|
|
||
|
if(ieKey == dojo.keys.LEFT_ARROW){
|
||
|
if((str1.charAt(cursorEnd-1) == LRM)
|
||
|
&& (cursorStart == cursorEnd)){
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem,cursorStart - 1, cursorEnd - 1);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if(ieKey == dojo.keys.RIGHT_ARROW){
|
||
|
if(str1.charAt(cursorEnd-1) == LRM){
|
||
|
cursorEnd1 = cursorEnd + 1;
|
||
|
if(cursorStart == cursorEnd){
|
||
|
cursorStart1 = cursorStart + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem, cursorStart1, cursorEnd1);
|
||
|
return;
|
||
|
}
|
||
|
}else{ //Firefox
|
||
|
if(ieKey == dojo.keys.LEFT_ARROW){
|
||
|
if(str1.charAt(cursorEnd-1) == LRM){
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem, cursorStart - 1, cursorEnd - 1);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
if(ieKey == dojo.keys.RIGHT_ARROW){
|
||
|
if(str1.charAt(cursorEnd-1) == LRM){
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem, cursorStart + 1, cursorEnd + 1);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var str2 = dojox.string.BidiComplex.createDisplayString(str1, elem.alt);
|
||
|
|
||
|
if(str1 != str2)
|
||
|
{
|
||
|
window.status = str1 + " c=" + cursorEnd;
|
||
|
elem.value = str2;
|
||
|
|
||
|
if((ieKey == dojo.keys.DELETE) && (str2.charAt(cursorEnd)==LRM)){
|
||
|
elem.value = str2.substring(0, cursorEnd) + str2.substring(cursorEnd+2, str2.length);
|
||
|
}
|
||
|
|
||
|
if(ieKey == dojo.keys.DELETE){
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem,cursorStart,cursorEnd);
|
||
|
}else if(ieKey == dojo.keys.BACKSPACE){
|
||
|
if((_str0.length >= cursorEnd) && (_str0.charAt(cursorEnd-1)==LRM)){
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem, cursorStart - 1, cursorEnd - 1);
|
||
|
}else{
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem, cursorStart, cursorEnd);
|
||
|
}
|
||
|
}else if(elem.value.charAt(cursorEnd) != LRM){
|
||
|
dojox.string.BidiComplex._setSelectedRange(elem, cursorStart + 1, cursorEnd + 1);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
dojox.string.BidiComplex._processCopy = function(elem, text, isReverse){
|
||
|
// summary:
|
||
|
// This function strips the unicode directional controls when the text copied to the Clipboard
|
||
|
|
||
|
if(text == null){
|
||
|
if(dojo.isIE){
|
||
|
var range = document.selection.createRange();
|
||
|
text = range.text;
|
||
|
}else{
|
||
|
text = elem.value.substring(elem.selectionStart, elem.selectionEnd);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var textToClipboard = dojox.string.BidiComplex.stripSpecialCharacters(text);
|
||
|
|
||
|
if(dojo.isIE){
|
||
|
window.clipboardData.setData("Text", textToClipboard);
|
||
|
}
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
dojox.string.BidiComplex._ceCopyText = function(elem){
|
||
|
if(dojo.isIE){
|
||
|
elem.returnValue = false;
|
||
|
}
|
||
|
return dojox.string.BidiComplex._processCopy(elem, null, false);
|
||
|
};
|
||
|
|
||
|
dojox.string.BidiComplex._ceCutText = function(elem){
|
||
|
|
||
|
var ret = dojox.string.BidiComplex._processCopy(elem, null, false);
|
||
|
if(!ret){
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
if(dojo.isIE){
|
||
|
// curPos = elem.selectionStart;
|
||
|
document.selection.clear();
|
||
|
}else{
|
||
|
var curPos = elem.selectionStart;
|
||
|
elem.value = elem.value.substring(0, curPos) + elem.value.substring(elem.selectionEnd);
|
||
|
elem.setSelectionRange(curPos, curPos);
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
};
|
||
|
|
||
|
// is there dijit code to do this?
|
||
|
dojox.string.BidiComplex._getCaretPos = function(event, elem){
|
||
|
if(dojo.isIE){
|
||
|
var position = 0,
|
||
|
range = document.selection.createRange().duplicate(),
|
||
|
range2 = range.duplicate(),
|
||
|
rangeLength = range.text.length;
|
||
|
|
||
|
if(elem.type == "textarea"){
|
||
|
range2.moveToElementText(elem);
|
||
|
}else{
|
||
|
range2.expand('textedit');
|
||
|
}
|
||
|
while(range.compareEndPoints('StartToStart', range2) > 0){
|
||
|
range.moveStart('character', -1);
|
||
|
++position;
|
||
|
}
|
||
|
|
||
|
return [position, position + rangeLength];
|
||
|
}
|
||
|
|
||
|
return [event.target.selectionStart, event.target.selectionEnd];
|
||
|
};
|
||
|
|
||
|
// is there dijit code to do this?
|
||
|
dojox.string.BidiComplex._setSelectedRange = function(elem,selectionStart,selectionEnd){
|
||
|
if(dojo.isIE){
|
||
|
var range = elem.createTextRange();
|
||
|
if(range){
|
||
|
if(elem.type == "textarea"){
|
||
|
range.moveToElementText(elem);
|
||
|
}else{
|
||
|
range.expand('textedit');
|
||
|
}
|
||
|
|
||
|
range.collapse();
|
||
|
range.moveEnd('character', selectionEnd);
|
||
|
range.moveStart('character', selectionStart);
|
||
|
range.select();
|
||
|
}
|
||
|
}else{
|
||
|
elem.selectionStart = selectionStart;
|
||
|
elem.selectionEnd = selectionEnd;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
var _isBidiChar = function(c){
|
||
|
return (c >= '\u0030' && c <= '\u0039') || (c > '\u00ff');
|
||
|
};
|
||
|
|
||
|
var _isLatinChar = function(c){
|
||
|
return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A');
|
||
|
};
|
||
|
|
||
|
var _isCharBeforeBiDiChar = function(buffer, i, previous){
|
||
|
while(i > 0){
|
||
|
if(i == previous){
|
||
|
return false;
|
||
|
}
|
||
|
i--;
|
||
|
if(_isBidiChar(buffer.charAt(i))){
|
||
|
return true;
|
||
|
}
|
||
|
if(_isLatinChar(buffer.charAt(i))){
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return false;
|
||
|
};
|
||
|
|
||
|
|
||
|
dojox.string.BidiComplex._parse = function(/*String*/str, /*String*/pattern){
|
||
|
var previous = -1, segmentsPointers = [];
|
||
|
var delimiters = {
|
||
|
FILE_PATH: "/\\:.",
|
||
|
URL: "/:.?=&#",
|
||
|
XPATH: "/\\:.<>=[]",
|
||
|
EMAIL: "<>@.,;"
|
||
|
}[pattern];
|
||
|
|
||
|
switch(pattern){
|
||
|
case "FILE_PATH":
|
||
|
case "URL":
|
||
|
case "XPATH":
|
||
|
dojo.forEach(str, function(ch, i){
|
||
|
if(delimiters.indexOf(ch) >= 0 && _isCharBeforeBiDiChar(str, i, previous)){
|
||
|
previous = i;
|
||
|
segmentsPointers.push(i);
|
||
|
}
|
||
|
});
|
||
|
break;
|
||
|
case "EMAIL":
|
||
|
var inQuotes = false; // FIXME: unused?
|
||
|
|
||
|
dojo.forEach(str, function(ch, i){
|
||
|
if(ch== '\"'){
|
||
|
if(_isCharBeforeBiDiChar(str, i, previous)){
|
||
|
previous = i;
|
||
|
segmentsPointers.push(i);
|
||
|
}
|
||
|
i++;
|
||
|
var i1 = str.indexOf('\"', i);
|
||
|
if(i1 >= i){
|
||
|
i = i1;
|
||
|
}
|
||
|
if(_isCharBeforeBiDiChar(str, i, previous)){
|
||
|
previous = i;
|
||
|
segmentsPointers.push(i);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(delimiters.indexOf(ch) >= 0 && _isCharBeforeBiDiChar(str, i, previous)){
|
||
|
previous = i;
|
||
|
segmentsPointers.push(i);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return segmentsPointers;
|
||
|
};
|
||
|
})();
|