source: Dev/branches/rest-dojo-ui/client/dojox/charting/BidiSupport.js @ 256

Last change on this file since 256 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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