BidiSupport.js 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. define("dojox/charting/BidiSupport", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/array", "dojo/_base/sniff",
  2. "dojo/dom","dojo/dom-construct",
  3. "dojox/gfx", "dojox/gfx/_gfxBidiSupport", "./Chart", "./axis2d/common", "dojox/string/BidiEngine", "dojox/lang/functional"],
  4. function(lang, html, arr, has, dom, domConstruct, g, gBidi, Chart, da, BidiEngine, df){
  5. var bidiEngine = new BidiEngine();
  6. lang.extend(Chart, {
  7. // summary:
  8. // Add support for bidi scripts.
  9. // description:
  10. // Bidi stands for support for languages with a bidirectional script.
  11. // There's a special need for displaying BIDI text in rtl direction
  12. // in ltr GUI, sometimes needed auto support.
  13. // dojox.charting does not support control over base text direction provided in Dojo.
  14. // textDir: String
  15. // Bi-directional support, the main variable which is responsible for the direction of the text.
  16. // The text direction can be different than the GUI direction by using this parameter.
  17. // Allowed values:
  18. // 1. "ltr"
  19. // 2. "rtl"
  20. // 3. "auto" - contextual the direction of a text defined by first strong letter.
  21. // By default is as the page direction.
  22. textDir:"",
  23. getTextDir: function(/*String*/text){
  24. // summary:
  25. // Return direction of the text.
  26. // description:
  27. // If textDir is ltr or rtl returns the value.
  28. // If it's auto, calls to another function that responsible
  29. // for checking the value, and defining the direction.
  30. // text:
  31. // Used in case textDir is "auto", this case the direction is according to the first
  32. // strong (directionally - which direction is strong defined) letter.
  33. // tags:
  34. // protected.
  35. var textDir = this.textDir == "auto" ? bidiEngine.checkContextual(text) : this.textDir;
  36. // providing default value
  37. if(!textDir){
  38. textDir = html.style(this.node,"direction");
  39. }
  40. return textDir;
  41. },
  42. postscript: function(node,args){
  43. // summary:
  44. // Kicks off chart instantiation.
  45. // description:
  46. // Used for setting the textDir of the chart.
  47. // tags:
  48. // private
  49. // validate textDir
  50. var textDir = args ? (args["textDir"] ? validateTextDir(args["textDir"]) : "") : "";
  51. // if textDir wasn't defined or was defined wrong, apply default value
  52. textDir = textDir ? textDir : html.style(this.node,"direction");
  53. this.textDir = textDir;
  54. this.surface.textDir = textDir;
  55. // two data structures, used for storing data for further enablement to change
  56. // textDir dynamically
  57. this.htmlElementsRegistry = [];
  58. this.truncatedLabelsRegistry = [];
  59. },
  60. setTextDir: function(/*String*/ newTextDir, obj){
  61. // summary:
  62. // Setter for the textDir attribute.
  63. // description:
  64. // Allows dynamically set the textDir, goes over all the text-children and
  65. // updates their base text direction.
  66. // tags:
  67. // public
  68. if(newTextDir == this.textDir){
  69. return this;
  70. }
  71. if(validateTextDir(newTextDir) != null){
  72. this.textDir = newTextDir;
  73. // set automatically all the gfx objects that were created by this surface
  74. // (groups, text objects)
  75. this.surface.setTextDir(newTextDir);
  76. // truncated labels that were created with gfx creator need to recalculate dir
  77. // for case like: "111111A" (A stands for bidi character) and the truncation
  78. // is "111..." If the textDir is auto, the display should be: "...111" but in gfx
  79. // case we will get "111...". Because this.surface.setTextDir will calculate the dir of truncated
  80. // label, which value is "111..." but th real is "111111A".
  81. // each time we created a gfx truncated label we stored it in the truncatedLabelsRegistry, so update now
  82. // the registry.
  83. if(this.truncatedLabelsRegistry && newTextDir == "auto"){
  84. arr.forEach(this.truncatedLabelsRegistry, function(elem){
  85. var tDir = this.getTextDir(elem["label"]);
  86. if(elem["element"].textDir != tDir){
  87. elem["element"].setShape({textDir: tDir});
  88. }
  89. }, this);
  90. }
  91. // re-render axes with html labels. for recalculation of the labels
  92. // positions etc.
  93. // create array of keys for all the axis in chart
  94. var axesKeyArr = df.keys(this.axes);
  95. if(axesKeyArr.length > 0){
  96. // iterate over the axes, and for each that have html labels render it.
  97. arr.forEach(axesKeyArr, function(key, index, arr){
  98. // get the axis
  99. var axis = this.axes[key];
  100. // if the axis has html labels
  101. if(axis.htmlElements[0]){
  102. axis.dirty = true;
  103. axis.render(this.dim, this.offsets);
  104. }
  105. },this);
  106. // recreate title
  107. if(this.title){
  108. var forceHtmlLabels = (g.renderer == "canvas"),
  109. labelType = forceHtmlLabels || !has("ie") && !has("opera") ? "html" : "gfx",
  110. tsize = g.normalizedLength(g.splitFontString(this.titleFont).size);
  111. // remove the title
  112. domConstruct.destroy(this.chartTitle);
  113. this.chartTitle =null;
  114. // create the new title
  115. this.chartTitle = da.createText[labelType](
  116. this,
  117. this.surface,
  118. this.dim.width/2,
  119. this.titlePos=="top" ? tsize + this.margins.t : this.dim.height - this.margins.b,
  120. "middle",
  121. this.title,
  122. this.titleFont,
  123. this.titleFontColor
  124. );
  125. }
  126. }else{
  127. // case of pies, spiders etc.
  128. arr.forEach(this.htmlElementsRegistry, function(elem, index, arr){
  129. var tDir = newTextDir == "auto" ? this.getTextDir(elem[4]) : newTextDir;
  130. if(elem[0].children[0] && elem[0].children[0].dir != tDir){
  131. dom.destroy(elem[0].children[0]);
  132. elem[0].children[0] = da.createText["html"]
  133. (this, this.surface, elem[1], elem[2], elem[3], elem[4], elem[5], elem[6]).children[0];
  134. }
  135. },this);
  136. }
  137. }
  138. },
  139. truncateBidi: function(elem, label, labelType){
  140. // summary:
  141. // Enables bidi support for truncated labels.
  142. // description:
  143. // Can be two types of labels: html or gfx.
  144. // gfx labels:
  145. // Need to be stored in registry to be used when the textDir will be set dynamically.
  146. // Additional work on truncated labels is needed for case as 111111A (A stands for "bidi" character rtl directioned).
  147. // let say in this case the truncation is "111..." If the textDir is auto, the display should be: "...111" but in gfx
  148. // case we will get "111...". Because this.surface.setTextDir will calculate the dir of truncated
  149. // label, which value is "111..." but th real is "111111A".
  150. // each time we created a gfx truncated label we store it in the truncatedLabelsRegistry.
  151. // html labels:
  152. // no need for repository (stored in another place). Here we only need to update the current dir according to textDir.
  153. // tags:
  154. // private
  155. if(labelType == "gfx"){
  156. // store truncated gfx labels in the data structure.
  157. this.truncatedLabelsRegistry.push({element: elem, label: label});
  158. if(this.textDir == "auto"){
  159. elem.setShape({textDir: this.getTextDir(label)});
  160. }
  161. }
  162. if(labelType == "html" && this.textDir == "auto"){
  163. elem.children[0].dir = this.getTextDir(label);
  164. }
  165. }
  166. });
  167. var extendMethod = function(obj, method, bundleByPrototype, before, after){
  168. // Some helper function. Used for extending method of obj.
  169. // obj: Object
  170. // The obj we overriding it's method.
  171. // method: String
  172. // The method that is extended, the original method is called before or after
  173. // functions that passed to extendMethod.
  174. // bundleByPrototype: boolean
  175. // There's two methods to extend, using prototype or not.
  176. // before: function
  177. // If defined this function will be executed before the original method.
  178. // after: function
  179. // If defined this function will be executed after the original method.
  180. if(bundleByPrototype){
  181. var old = obj.prototype[method];
  182. obj.prototype[method] =
  183. function(){
  184. var rBefore;
  185. if (before){
  186. rBefore = before.apply(this, arguments);
  187. }
  188. var r = old.apply(this, rBefore);
  189. if (after){
  190. r = after.call(this, r, arguments);
  191. }
  192. return r;
  193. };
  194. }else{
  195. var old = lang.clone(obj[method]);
  196. obj[method] =
  197. function(){
  198. var rBefore;
  199. if (before){
  200. rBefore = before.apply(this, arguments);
  201. }
  202. var r = old.apply(this, arguments);
  203. if (after){
  204. after(r, arguments);
  205. }
  206. return r;
  207. };
  208. }
  209. };
  210. var labelPreprocess = function(elem, chart, label, truncatedLabel, font, elemType){
  211. // aditional preprocessing of the labels, needed for rtl base text direction in LTR
  212. // GUI, or for ltr base text direction for RTL GUI.
  213. var isChartDirectionRtl = (html.style(chart.node,"direction") == "rtl");
  214. var isBaseTextDirRtl = (chart.getTextDir(label) == "rtl");
  215. if(isBaseTextDirRtl && !isChartDirectionRtl){
  216. label = "<span dir='rtl'>" + label +"</span>";
  217. }
  218. if(!isBaseTextDirRtl && isChartDirectionRtl){
  219. label = "<span dir='ltr'>" + label +"</span>";
  220. }
  221. return arguments;
  222. };
  223. // connect labelPreprocess to run before labelTooltip.
  224. // patch it only is available
  225. if(dojox.charting.axis2d && dojox.charting.axis2d.Default){
  226. extendMethod(dojox.charting.axis2d.Default,"labelTooltip",true, labelPreprocess, null);
  227. //extendMethod(dijit,"showTooltip",false, labelPreprocess, null);
  228. }
  229. function htmlCreateText(r, agumentsArr){
  230. // function to register HTML elements that created by html.createText, this array
  231. // needed for allowing to change textDir dynamically.
  232. agumentsArr[0].htmlElementsRegistry.push([r, agumentsArr[2], agumentsArr[3], agumentsArr[4], agumentsArr[5], agumentsArr[6], agumentsArr[7]]);
  233. }
  234. extendMethod(da.createText,"html", false, null, htmlCreateText);
  235. function validateTextDir(textDir){
  236. return /^(ltr|rtl|auto)$/.test(textDir) ? textDir : null;
  237. }
  238. });