BidiComplex.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.string.BidiComplex"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.string.BidiComplex"] = true;
  8. dojo.provide("dojox.string.BidiComplex");
  9. dojo.experimental("dojox.string.BidiComplex");
  10. // summary:
  11. // BiDiComplex module handles complex expression issues known when using BiDi characters
  12. // in File Paths, URLs, E-mail Address, XPATH, etc.
  13. // this module adds property listeners to the text fields to correct the text representation
  14. // in both static text and dynamic text during user input.
  15. (function(){
  16. var _str0 = []; //FIXME: shared reference here among various functions means the functions can't be reused
  17. dojox.string.BidiComplex.attachInput = function(/*DOMNode*/field, /*String*/pattern){
  18. // summary:
  19. // Attach key listeners to the INPUT field to accomodate dynamic complex BiDi expressions
  20. // field: INPUT DOM node
  21. // pattern: Complex Expression Pattern type. One of "FILE_PATH", "URL", "EMAIL", "XPATH"
  22. field.alt = pattern;
  23. dojo.connect(field, "onkeydown", this, "_ceKeyDown");
  24. dojo.connect(field, "onkeyup", this, "_ceKeyUp");
  25. dojo.connect(field, "oncut", this, "_ceCutText");
  26. dojo.connect(field, "oncopy", this, "_ceCopyText");
  27. field.value = dojox.string.BidiComplex.createDisplayString(field.value, field.alt);
  28. };
  29. dojox.string.BidiComplex.createDisplayString = function(/*String*/str, /*String*/pattern){
  30. // summary:
  31. // Create the display string by adding the Unicode direction Markers
  32. // pattern: Complex Expression Pattern type. One of "FILE_PATH", "URL", "EMAIL", "XPATH"
  33. str = dojox.string.BidiComplex.stripSpecialCharacters(str);
  34. var segmentsPointers = dojox.string.BidiComplex._parse(str, pattern);
  35. var buf = '\u202A'/*LRE*/ + str;
  36. var shift = 1;
  37. dojo.forEach(segmentsPointers, function(n){
  38. if(n != null){
  39. var preStr = buf.substring(0, n + shift);
  40. var postStr = buf.substring(n + shift, buf.length);
  41. buf = preStr + '\u200E'/*LRM*/ + postStr;
  42. shift++;
  43. }
  44. });
  45. return buf;
  46. };
  47. dojox.string.BidiComplex.stripSpecialCharacters = function(str){
  48. // summary:
  49. // removes all Unicode directional markers from the string
  50. return str.replace(/[\u200E\u200F\u202A-\u202E]/g, ""); // String
  51. };
  52. dojox.string.BidiComplex._ceKeyDown = function(event){
  53. var elem = dojo.isIE ? event.srcElement : event.target;
  54. _str0 = elem.value;
  55. };
  56. dojox.string.BidiComplex._ceKeyUp = function(event){
  57. var LRM = '\u200E';
  58. var elem = dojo.isIE ? event.srcElement : event.target;
  59. var str1 = elem.value;
  60. var ieKey = event.keyCode;
  61. if((ieKey == dojo.keys.HOME)
  62. || (ieKey == dojo.keys.END)
  63. || (ieKey == dojo.keys.SHIFT)){
  64. return;
  65. }
  66. var cursorStart, cursorEnd;
  67. var selection = dojox.string.BidiComplex._getCaretPos(event, elem);
  68. if(selection){
  69. cursorStart = selection[0];
  70. cursorEnd = selection[1];
  71. }
  72. //Jump over a cursor processing
  73. if(dojo.isIE){
  74. var cursorStart1 = cursorStart, cursorEnd1 = cursorEnd;
  75. if(ieKey == dojo.keys.LEFT_ARROW){
  76. if((str1.charAt(cursorEnd-1) == LRM)
  77. && (cursorStart == cursorEnd)){
  78. dojox.string.BidiComplex._setSelectedRange(elem,cursorStart - 1, cursorEnd - 1);
  79. }
  80. return;
  81. }
  82. if(ieKey == dojo.keys.RIGHT_ARROW){
  83. if(str1.charAt(cursorEnd-1) == LRM){
  84. cursorEnd1 = cursorEnd + 1;
  85. if(cursorStart == cursorEnd){
  86. cursorStart1 = cursorStart + 1;
  87. }
  88. }
  89. dojox.string.BidiComplex._setSelectedRange(elem, cursorStart1, cursorEnd1);
  90. return;
  91. }
  92. }else{ //Firefox
  93. if(ieKey == dojo.keys.LEFT_ARROW){
  94. if(str1.charAt(cursorEnd-1) == LRM){
  95. dojox.string.BidiComplex._setSelectedRange(elem, cursorStart - 1, cursorEnd - 1);
  96. }
  97. return;
  98. }
  99. if(ieKey == dojo.keys.RIGHT_ARROW){
  100. if(str1.charAt(cursorEnd-1) == LRM){
  101. dojox.string.BidiComplex._setSelectedRange(elem, cursorStart + 1, cursorEnd + 1);
  102. }
  103. return;
  104. }
  105. }
  106. var str2 = dojox.string.BidiComplex.createDisplayString(str1, elem.alt);
  107. if(str1 != str2)
  108. {
  109. window.status = str1 + " c=" + cursorEnd;
  110. elem.value = str2;
  111. if((ieKey == dojo.keys.DELETE) && (str2.charAt(cursorEnd)==LRM)){
  112. elem.value = str2.substring(0, cursorEnd) + str2.substring(cursorEnd+2, str2.length);
  113. }
  114. if(ieKey == dojo.keys.DELETE){
  115. dojox.string.BidiComplex._setSelectedRange(elem,cursorStart,cursorEnd);
  116. }else if(ieKey == dojo.keys.BACKSPACE){
  117. if((_str0.length >= cursorEnd) && (_str0.charAt(cursorEnd-1)==LRM)){
  118. dojox.string.BidiComplex._setSelectedRange(elem, cursorStart - 1, cursorEnd - 1);
  119. }else{
  120. dojox.string.BidiComplex._setSelectedRange(elem, cursorStart, cursorEnd);
  121. }
  122. }else if(elem.value.charAt(cursorEnd) != LRM){
  123. dojox.string.BidiComplex._setSelectedRange(elem, cursorStart + 1, cursorEnd + 1);
  124. }
  125. }
  126. };
  127. dojox.string.BidiComplex._processCopy = function(elem, text, isReverse){
  128. // summary:
  129. // This function strips the unicode directional controls when the text copied to the Clipboard
  130. if(text == null){
  131. if(dojo.isIE){
  132. var range = document.selection.createRange();
  133. text = range.text;
  134. }else{
  135. text = elem.value.substring(elem.selectionStart, elem.selectionEnd);
  136. }
  137. }
  138. var textToClipboard = dojox.string.BidiComplex.stripSpecialCharacters(text);
  139. if(dojo.isIE){
  140. window.clipboardData.setData("Text", textToClipboard);
  141. }
  142. return true;
  143. };
  144. dojox.string.BidiComplex._ceCopyText = function(elem){
  145. if(dojo.isIE){
  146. elem.returnValue = false;
  147. }
  148. return dojox.string.BidiComplex._processCopy(elem, null, false);
  149. };
  150. dojox.string.BidiComplex._ceCutText = function(elem){
  151. var ret = dojox.string.BidiComplex._processCopy(elem, null, false);
  152. if(!ret){
  153. return false;
  154. }
  155. if(dojo.isIE){
  156. // curPos = elem.selectionStart;
  157. document.selection.clear();
  158. }else{
  159. var curPos = elem.selectionStart;
  160. elem.value = elem.value.substring(0, curPos) + elem.value.substring(elem.selectionEnd);
  161. elem.setSelectionRange(curPos, curPos);
  162. }
  163. return true;
  164. };
  165. // is there dijit code to do this?
  166. dojox.string.BidiComplex._getCaretPos = function(event, elem){
  167. if(dojo.isIE){
  168. var position = 0,
  169. range = document.selection.createRange().duplicate(),
  170. range2 = range.duplicate(),
  171. rangeLength = range.text.length;
  172. if(elem.type == "textarea"){
  173. range2.moveToElementText(elem);
  174. }else{
  175. range2.expand('textedit');
  176. }
  177. while(range.compareEndPoints('StartToStart', range2) > 0){
  178. range.moveStart('character', -1);
  179. ++position;
  180. }
  181. return [position, position + rangeLength];
  182. }
  183. return [event.target.selectionStart, event.target.selectionEnd];
  184. };
  185. // is there dijit code to do this?
  186. dojox.string.BidiComplex._setSelectedRange = function(elem,selectionStart,selectionEnd){
  187. if(dojo.isIE){
  188. var range = elem.createTextRange();
  189. if(range){
  190. if(elem.type == "textarea"){
  191. range.moveToElementText(elem);
  192. }else{
  193. range.expand('textedit');
  194. }
  195. range.collapse();
  196. range.moveEnd('character', selectionEnd);
  197. range.moveStart('character', selectionStart);
  198. range.select();
  199. }
  200. }else{
  201. elem.selectionStart = selectionStart;
  202. elem.selectionEnd = selectionEnd;
  203. }
  204. };
  205. var _isBidiChar = function(c){
  206. return (c >= '\u0030' && c <= '\u0039') || (c > '\u00ff');
  207. };
  208. var _isLatinChar = function(c){
  209. return (c >= '\u0041' && c <= '\u005A') || (c >= '\u0061' && c <= '\u007A');
  210. };
  211. var _isCharBeforeBiDiChar = function(buffer, i, previous){
  212. while(i > 0){
  213. if(i == previous){
  214. return false;
  215. }
  216. i--;
  217. if(_isBidiChar(buffer.charAt(i))){
  218. return true;
  219. }
  220. if(_isLatinChar(buffer.charAt(i))){
  221. return false;
  222. }
  223. }
  224. return false;
  225. };
  226. dojox.string.BidiComplex._parse = function(/*String*/str, /*String*/pattern){
  227. var previous = -1, segmentsPointers = [];
  228. var delimiters = {
  229. FILE_PATH: "/\\:.",
  230. URL: "/:.?=&#",
  231. XPATH: "/\\:.<>=[]",
  232. EMAIL: "<>@.,;"
  233. }[pattern];
  234. switch(pattern){
  235. case "FILE_PATH":
  236. case "URL":
  237. case "XPATH":
  238. dojo.forEach(str, function(ch, i){
  239. if(delimiters.indexOf(ch) >= 0 && _isCharBeforeBiDiChar(str, i, previous)){
  240. previous = i;
  241. segmentsPointers.push(i);
  242. }
  243. });
  244. break;
  245. case "EMAIL":
  246. var inQuotes = false; // FIXME: unused?
  247. dojo.forEach(str, function(ch, i){
  248. if(ch== '\"'){
  249. if(_isCharBeforeBiDiChar(str, i, previous)){
  250. previous = i;
  251. segmentsPointers.push(i);
  252. }
  253. i++;
  254. var i1 = str.indexOf('\"', i);
  255. if(i1 >= i){
  256. i = i1;
  257. }
  258. if(_isCharBeforeBiDiChar(str, i, previous)){
  259. previous = i;
  260. segmentsPointers.push(i);
  261. }
  262. }
  263. if(delimiters.indexOf(ch) >= 0 && _isCharBeforeBiDiChar(str, i, previous)){
  264. previous = i;
  265. segmentsPointers.push(i);
  266. }
  267. });
  268. }
  269. return segmentsPointers;
  270. };
  271. })();
  272. }