//>>built define("dojox/charting/BidiSupport", ["dojo/_base/lang", "dojo/_base/html", "dojo/_base/array", "dojo/_base/sniff", "dojo/dom","dojo/dom-construct", "dojox/gfx", "dojox/gfx/_gfxBidiSupport", "./Chart", "./axis2d/common", "dojox/string/BidiEngine", "dojox/lang/functional"], function(lang, html, arr, has, dom, domConstruct, g, gBidi, Chart, da, BidiEngine, df){ var bidiEngine = new BidiEngine(); lang.extend(Chart, { // summary: // Add support for bidi scripts. // description: // Bidi stands for support for languages with a bidirectional script. // There's a special need for displaying BIDI text in rtl direction // in ltr GUI, sometimes needed auto support. // dojox.charting does not support control over base text direction provided in Dojo. // textDir: String // Bi-directional support, the main variable which is responsible for the direction of the text. // The text direction can be different than the GUI direction by using this parameter. // Allowed values: // 1. "ltr" // 2. "rtl" // 3. "auto" - contextual the direction of a text defined by first strong letter. // By default is as the page direction. textDir:"", getTextDir: function(/*String*/text){ // summary: // Return direction of the text. // description: // If textDir is ltr or rtl returns the value. // If it's auto, calls to another function that responsible // for checking the value, and defining the direction. // text: // Used in case textDir is "auto", this case the direction is according to the first // strong (directionally - which direction is strong defined) letter. // tags: // protected. var textDir = this.textDir == "auto" ? bidiEngine.checkContextual(text) : this.textDir; // providing default value if(!textDir){ textDir = html.style(this.node,"direction"); } return textDir; }, postscript: function(node,args){ // summary: // Kicks off chart instantiation. // description: // Used for setting the textDir of the chart. // tags: // private // validate textDir var textDir = args ? (args["textDir"] ? validateTextDir(args["textDir"]) : "") : ""; // if textDir wasn't defined or was defined wrong, apply default value textDir = textDir ? textDir : html.style(this.node,"direction"); this.textDir = textDir; this.surface.textDir = textDir; // two data structures, used for storing data for further enablement to change // textDir dynamically this.htmlElementsRegistry = []; this.truncatedLabelsRegistry = []; }, setTextDir: function(/*String*/ newTextDir, obj){ // summary: // Setter for the textDir attribute. // description: // Allows dynamically set the textDir, goes over all the text-children and // updates their base text direction. // tags: // public if(newTextDir == this.textDir){ return this; } if(validateTextDir(newTextDir) != null){ this.textDir = newTextDir; // set automatically all the gfx objects that were created by this surface // (groups, text objects) this.surface.setTextDir(newTextDir); // truncated labels that were created with gfx creator need to recalculate dir // for case like: "111111A" (A stands for bidi character) and the truncation // is "111..." If the textDir is auto, the display should be: "...111" but in gfx // case we will get "111...". Because this.surface.setTextDir will calculate the dir of truncated // label, which value is "111..." but th real is "111111A". // each time we created a gfx truncated label we stored it in the truncatedLabelsRegistry, so update now // the registry. if(this.truncatedLabelsRegistry && newTextDir == "auto"){ arr.forEach(this.truncatedLabelsRegistry, function(elem){ var tDir = this.getTextDir(elem["label"]); if(elem["element"].textDir != tDir){ elem["element"].setShape({textDir: tDir}); } }, this); } // re-render axes with html labels. for recalculation of the labels // positions etc. // create array of keys for all the axis in chart var axesKeyArr = df.keys(this.axes); if(axesKeyArr.length > 0){ // iterate over the axes, and for each that have html labels render it. arr.forEach(axesKeyArr, function(key, index, arr){ // get the axis var axis = this.axes[key]; // if the axis has html labels if(axis.htmlElements[0]){ axis.dirty = true; axis.render(this.dim, this.offsets); } },this); // recreate title if(this.title){ var forceHtmlLabels = (g.renderer == "canvas"), labelType = forceHtmlLabels || !has("ie") && !has("opera") ? "html" : "gfx", tsize = g.normalizedLength(g.splitFontString(this.titleFont).size); // remove the title domConstruct.destroy(this.chartTitle); this.chartTitle =null; // create the new title this.chartTitle = da.createText[labelType]( this, this.surface, this.dim.width/2, this.titlePos=="top" ? tsize + this.margins.t : this.dim.height - this.margins.b, "middle", this.title, this.titleFont, this.titleFontColor ); } }else{ // case of pies, spiders etc. arr.forEach(this.htmlElementsRegistry, function(elem, index, arr){ var tDir = newTextDir == "auto" ? this.getTextDir(elem[4]) : newTextDir; if(elem[0].children[0] && elem[0].children[0].dir != tDir){ dom.destroy(elem[0].children[0]); elem[0].children[0] = da.createText["html"] (this, this.surface, elem[1], elem[2], elem[3], elem[4], elem[5], elem[6]).children[0]; } },this); } } }, truncateBidi: function(elem, label, labelType){ // summary: // Enables bidi support for truncated labels. // description: // Can be two types of labels: html or gfx. // gfx labels: // Need to be stored in registry to be used when the textDir will be set dynamically. // Additional work on truncated labels is needed for case as 111111A (A stands for "bidi" character rtl directioned). // let say in this case the truncation is "111..." If the textDir is auto, the display should be: "...111" but in gfx // case we will get "111...". Because this.surface.setTextDir will calculate the dir of truncated // label, which value is "111..." but th real is "111111A". // each time we created a gfx truncated label we store it in the truncatedLabelsRegistry. // html labels: // no need for repository (stored in another place). Here we only need to update the current dir according to textDir. // tags: // private if(labelType == "gfx"){ // store truncated gfx labels in the data structure. this.truncatedLabelsRegistry.push({element: elem, label: label}); if(this.textDir == "auto"){ elem.setShape({textDir: this.getTextDir(label)}); } } if(labelType == "html" && this.textDir == "auto"){ elem.children[0].dir = this.getTextDir(label); } } }); var extendMethod = function(obj, method, bundleByPrototype, before, after){ // Some helper function. Used for extending method of obj. // obj: Object // The obj we overriding it's method. // method: String // The method that is extended, the original method is called before or after // functions that passed to extendMethod. // bundleByPrototype: boolean // There's two methods to extend, using prototype or not. // before: function // If defined this function will be executed before the original method. // after: function // If defined this function will be executed after the original method. if(bundleByPrototype){ var old = obj.prototype[method]; obj.prototype[method] = function(){ var rBefore; if (before){ rBefore = before.apply(this, arguments); } var r = old.apply(this, rBefore); if (after){ r = after.call(this, r, arguments); } return r; }; }else{ var old = lang.clone(obj[method]); obj[method] = function(){ var rBefore; if (before){ rBefore = before.apply(this, arguments); } var r = old.apply(this, arguments); if (after){ after(r, arguments); } return r; }; } }; var labelPreprocess = function(elem, chart, label, truncatedLabel, font, elemType){ // aditional preprocessing of the labels, needed for rtl base text direction in LTR // GUI, or for ltr base text direction for RTL GUI. var isChartDirectionRtl = (html.style(chart.node,"direction") == "rtl"); var isBaseTextDirRtl = (chart.getTextDir(label) == "rtl"); if(isBaseTextDirRtl && !isChartDirectionRtl){ label = "" + label +""; } if(!isBaseTextDirRtl && isChartDirectionRtl){ label = "" + label +""; } return arguments; }; // connect labelPreprocess to run before labelTooltip. // patch it only is available if(dojox.charting.axis2d && dojox.charting.axis2d.Default){ extendMethod(dojox.charting.axis2d.Default,"labelTooltip",true, labelPreprocess, null); //extendMethod(dijit,"showTooltip",false, labelPreprocess, null); } function htmlCreateText(r, agumentsArr){ // function to register HTML elements that created by html.createText, this array // needed for allowing to change textDir dynamically. agumentsArr[0].htmlElementsRegistry.push([r, agumentsArr[2], agumentsArr[3], agumentsArr[4], agumentsArr[5], agumentsArr[6], agumentsArr[7]]); } extendMethod(da.createText,"html", false, null, htmlCreateText); function validateTextDir(textDir){ return /^(ltr|rtl|auto)$/.test(textDir) ? textDir : null; } });