Move parseFontFaceDescriptor to CSSPropertyParser.cpp
[chromium-blink-merge.git] / third_party / WebKit / LayoutTests / svg / carto.net / resources / tabgroup.js
blobabf29bf82c15ccbbba7d84dfea234b6c6305f46b
1 /*
2 Scripts to create interactive tabs in SVG using ECMA script
3 Copyright (C) <2006>  <Andreas Neumann>
4 Version 1.2, 2006-04-03
5 neumann@karto.baug.ethz.ch
6 http://www.carto.net/
7 http://www.carto.net/neumann/
9 Credits:
10 * none so far
12 ----
14 Documentation: http://www.carto.net/papers/svg/gui/tabgroup/
16 ----
18 current version: 1.2.1
20 version history:
21 1.0 (2006-03-11)
22 initial version
24 1.1 (2006-04-03)
25 added ".moveTo(x,y)" and ".resize(width,height)" methods, added an additional g-element to hold transform values
27 1.2 (2006-06-19)
28 this.parentNode can now also be of type node reference (g or svg element); fixed a small bug when "hideContent" was set to true; changed this.parentGroup and introduced this.tabGroup
29 introduced id for group where content can be added, id name is: this.id+"__"+i+"_content"
31 1.2.1 (2006-07-07)
32 fixed a bug for multiline tabs (dy attribute of the tab texts). This bug was apparent when having more than two lines of text in the tabs
34 -------
37 This ECMA script library is free software; you can redistribute it and/or
38 modify it under the terms of the GNU Lesser General Public
39 License as published by the Free Software Foundation; either
40 version 2.1 of the License, or (at your option) any later version.
42 This library is distributed in the hope that it will be useful,
43 but WITHOUT ANY WARRANTY; without even the implied warranty of
44 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
45 Lesser General Public License for more details.
47 You should have received a copy of the GNU Lesser General Public
48 License along with this library (lesser_gpl.txt); if not, write to the Free Software
49 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
51 ----
53 original document site: http://www.carto.net/papers/svg/gui/tabgroup/
54 Please contact the author in case you want to use code or ideas commercially.
55 If you use this code, please include this copyright header, the included full
56 LGPL 2.1 text and read the terms provided in the LGPL 2.1 license
57 (http://www.gnu.org/copyleft/lesser.txt)
59 -------------------------------
61 Please report bugs and send improvements to neumann@karto.baug.ethz.ch
62 If you use this control, please link to the original (http://www.carto.net/papers/svg/gui/tabgroup/)
63 somewhere in the source-code-comment or the "about" of your project and give credits, thanks!
67 function tabgroup(id,parentNode,transx,transy,width,height,tabheight,cornerLeft,cornerRight,tabmargins,spaceBetweenTabs,tabStyles,activetabBGColor,tabwindowStyles,tabtextStyles,tabTitles,activeTabindex,hideContent,functionToCall) {
68     var nrArguments = 19;
69     var createTabgroup = true;
70     if (arguments.length == nrArguments) {
71         this.id = id;
72         this.parentNode = parentNode; //can be of type string (id) or node reference (svg or g node)
73         this.transx = transx;
74         this.transy = transy;
75         this.x = 0;
76         this.y = 0;
77         this.width = width;
78         this.height = height;
79         this.tabheight = tabheight;
80         this.cornerLeft = cornerLeft; //values are "rect","round","triangle"
81         this.cornerRight = cornerRight; //values are "rect","round","triangle"
82         this.tabmargins = tabmargins;
83         this.spaceBetweenTabs = spaceBetweenTabs;
84         this.tabStyles = tabStyles;
85         if (!this.tabStyles["fill"]) {
86             this.tabStyles["fill"] = "lightgray";
87         }
88         this.activetabBGColor = activetabBGColor;
89         this.tabwindowStyles = tabwindowStyles;
90         this.tabtextStyles = tabtextStyles;
91         if (!this.tabtextStyles["font-size"]) {
92             this.tabtextStyles["font-size"] = 15;
93         }
94         this.tabTitles = tabTitles;
95         if (this.tabTitles instanceof Array) {
96             if (this.tabTitles.length == 0) {
97                 createTabgroup = false;
98                 alert("Error ("+this.id+"): the array 'tabTitles' has no elements!");
99             }
100         }
101         else {
102             createTabgroup = false;
103             alert("Error ("+this.id+"): the array 'tabTitles' is not of type array!");
104         }
105         this.activeTabindex = activeTabindex;
106         if (this.activeTabindex >= this.tabTitles.length) {
107             createTabgroup = false;
108             this.outOfBoundMessage(this.activeTabindex);
109         }
110         this.hideContent = hideContent; //boolean, defines whether the display of a tab should be set to "none","inherit"
111         this.functionToCall = functionToCall;
112         if (!(typeof(this.functionToCall) == "function" || typeof(this.functionToCall) == "object" || typeof(this.functionToCall) == "undefined")) {
113             createTabgroup = false;
114             alert("Error ("+this.id+"): functionToCall is of type '"+typeof(this.functionToCall)+"' and not of type 'function', 'object' or 'undefined'");
115         }
116     }
117     else {
118         createTabgroup = false;
119         alert("Error ("+id+"): wrong nr of arguments! You have to pass over "+nrArguments+" parameters.");
120     }
121     if (createTabgroup) {
122         this.parentGroup = null; //later a node reference to the parent group
123         this.tabGroup = null; //later a reference to the group within the parentGroup
124         this.tabwindows = new Array();
125         this.timer = new Timer(this); //a Timer instance for calling the functionToCall
126         this.timerMs = 200; //a constant of this object that is used in conjunction with the timer - functionToCall is called after 200 ms
127         this.createTabGroup();
128     }
129     else {
130         alert("Could not create tabgroup with id '"+this.id+"' due to errors in the constructor parameters");
131     }
134 tabgroup.prototype.createTabGroup = function() {
135     var result = this.testParent();
136     if (result) {
137     this.tabGroup = document.createElementNS(svgNS,"g");
138     this.tabGroup.setAttributeNS(null,"transform","translate("+this.transx+","+this.transy+")");
139     this.parentGroup.appendChild(this.tabGroup);
140     //loop to create all tabs
141     var currentX = this.x;
142     for (var i=0;i<this.tabTitles.length;i++) {
143         currentLeft = currentX;
144         this.tabwindows[i] = new Array();
145         //create group
146         this.tabwindows[i]["group"] = document.createElementNS(svgNS,"g");
147         this.tabGroup.appendChild(this.tabwindows[i]["group"]);
148         //create tabTitle
149         var tabtitles = this.tabTitles[i].split("\n");
150         this.tabwindows[i]["tabTitle"] = document.createElementNS(svgNS,"text");
151         this.tabwindows[i]["tabTitle"].setAttributeNS(null,"y",this.y + this.tabtextStyles["font-size"]);
152         var value="";
153         for (var attrib in this.tabtextStyles) {
154             value = this.tabtextStyles[attrib];
155             if (attrib == "font-size") {
156                 value += "px";
157             }
158             this.tabwindows[i]["tabTitle"].setAttributeNS(null,attrib,value);
159         }
160         this.tabwindows[i]["tabTitle"].setAttributeNS(null,"pointer-events","none");
161         //create tspans and add text contents
162         for (var j=0;j<tabtitles.length;j++) {
163             var tspan = document.createElementNS(svgNS,"tspan");
164             tspan.setAttributeNS(null,"x",currentX+this.tabmargins);
165             var dy = this.tabtextStyles["font-size"]*1.1;
166             if (j == 0) {
167                 dy = 0;
168             }
169             tspan.setAttributeNS(null,"dy",dy);
170             var textNode = document.createTextNode(tabtitles[j]);
171             tspan.appendChild(textNode);
172             this.tabwindows[i]["tabTitle"].appendChild(tspan);
173         }
174         this.tabwindows[i]["group"].appendChild(this.tabwindows[i]["tabTitle"]);
175         //get bbox
176         var bbox = this.tabwindows[i]["tabTitle"].getBBox();
177         currentX = Math.round(currentLeft + this.tabmargins * 2 + bbox.width);
178         //check if text-anchor is middle and shift the x-values accordingly
179         if (this.tabtextStyles["text-anchor"]) {
180             if (this.tabtextStyles["text-anchor"] == "middle") {
181                 this.tabwindows[i]["tabTitle"].setAttributeNS(null,"transform","translate("+(bbox.width * 0.5)+" 0)");
182             }
183         }
184         //now draw tabwindow background
185         this.tabwindows[i]["tabbg"] = document.createElementNS(svgNS,"path");
186         for (var attrib in this.tabwindowStyles) {
187             this.tabwindows[i]["tabbg"].setAttributeNS(null,attrib,this.tabwindowStyles[attrib]);
188         }
189         //start the path for tab windows
190         var d = "M";
191         //left corner of tab
192         if (this.cornerLeft == "rect") {
193             d += currentLeft+" "+this.y;
194         }
195         if (this.cornerLeft == "triangle") {
196             d += currentLeft+" "+(this.y+this.tabmargins)+"L"+(currentLeft+this.tabmargins)+" "+this.y;
197         }
198         if (this.cornerLeft == "round") {
199             d += currentLeft+" "+(this.y+this.tabmargins)+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" -"+this.tabmargins;
200         }
201         //right corner of tab
202         if (this.cornerRight == "rect") {
203             d += "L"+currentX+" "+this.y;
204         }
205         if (this.cornerRight == "triangle") {
206             d += "L"+(currentX-this.tabmargins)+" "+this.y+"L"+currentX+" "+(this.y+this.tabmargins);
207         }
208         if (this.cornerRight == "round") {
209             d += "L"+(currentX-this.tabmargins)+" "+this.y+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" "+this.tabmargins;
210         }
211         d += "L"+currentX+" "+(this.y+this.tabheight);
212         //complete the path for tab
213         var dtab = d + "L"+currentLeft+" "+(this.y+this.tabheight)+"z";
214         //complete the path for tab window
215         d += "L"+(this.x+this.width)+" "+(this.y+this.tabheight)+"L"+(this.x+this.width)+" "+(this.y+this.height);
216         d += "L"+this.x+" "+(this.y+this.height);
217         if (currentLeft == this.x) {
218             d += "z";
219         }
220         else {
221             d += "L"+this.x+" "+(this.y+this.tabheight)+"L"+currentLeft+" "+(this.y+this.tabheight)+"z";
222         }
223         this.tabwindows[i]["tabbg"].setAttributeNS(null,"d",d);
224         this.tabwindows[i]["group"].insertBefore(this.tabwindows[i]["tabbg"],this.tabwindows[i]["tabTitle"]);
225         //create tab element
226         this.tabwindows[i]["tab"] = document.createElementNS(svgNS,"path");
227         for (var attrib in this.tabStyles) {
228             this.tabwindows[i]["tab"].setAttributeNS(null,attrib,this.tabStyles[attrib]);
229         }
230         this.tabwindows[i]["tab"].setAttributeNS(null,"d",dtab);
231         this.tabwindows[i]["tab"].setAttributeNS(null,"id",this.id+"__"+i);
232         this.tabwindows[i]["tab"].addEventListener("click",this,false);
233         this.tabwindows[i]["group"].insertBefore(this.tabwindows[i]["tab"],this.tabwindows[i]["tabTitle"]);
234         //create group for tab content
235         this.tabwindows[i]["content"] = document.createElementNS(svgNS,"g");
236         this.tabwindows[i]["content"].setAttributeNS(null,"id",this.id+"__"+i+"_content");
237         if (this.hideContent) {
238             this.tabwindows[i]["content"].setAttributeNS(null,"display","none");
239         }
240         this.tabwindows[i]["group"].appendChild(this.tabwindows[i]["content"]);
241         //set tab activate status
242         this.tabwindows[i].activeStatus = true;
243         //increment currentX with the space between tabs
244         currentX += this.spaceBetweenTabs;
245     }
246     //activate one tab
247     this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.activetabBGColor);
248     this.tabGroup.appendChild(this.tabwindows[this.activeTabindex]["group"]);
249     if (this.hideContent) {
250         this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","inherit");
251     }
252     }
253     else {
254         alert("could not create or reference 'parentNode' of tabgroup with id '"+this.id+"'");
255     }
258  //test if window group exists or create a new group at the end of the file
259 tabgroup.prototype.testParent = function() {
260     //test if of type object
261     var nodeValid = false;
262     if (typeof(this.parentNode) == "object") {
263         if (this.parentNode.nodeName == "svg" || this.parentNode.nodeName == "g") {
264             this.parentGroup = this.parentNode;
265             nodeValid = true;
266         }
267     }
268     else if (typeof(this.parentNode) == "string") { 
269         //first test if Windows group exists
270         if (!document.getElementById(this.parentNode)) {
271             this.parentGroup = document.createElementNS(svgNS,"g");
272             this.parentGroup.setAttributeNS(null,"id",this.parentNode);
273             document.documentElement.appendChild(this.parentGroup);
274             nodeValid = true;
275            }
276            else {
277                this.parentGroup = document.getElementById(this.parentNode);
278                nodeValid = true;
279            }
280        }
281        return nodeValid;
284 tabgroup.prototype.handleEvent = function(evt) {
285     var tab = evt.target;
286     var id = tab.getAttributeNS(null,"id");
287     var idArray = id.split("__");
288     var index = parseInt(idArray[1]);
289     this.activateTabByIndex(index,false);
290     //firefunction
291     this.timer.setTimeout("fireFunction",this.timerMs);
294 tabgroup.prototype.fireFunction = function() {
295     if (typeof(this.functionToCall) == "function") {
296         this.functionToCall(this.id,this.tabTitles[this.activeTabindex],this.activeTabindex);
297     }
298     if (typeof(this.functionToCall) == "object") {
299         this.functionToCall.tabActivated(this.id,this.tabTitles[this.activeTabindex],this.activeTabindex);
300     }
301     if (typeof(this.functionToCall) == undefined) {
302         return;
303     }
306 tabgroup.prototype.activateTabByIndex = function(tabindex,fireFunction) {
307     if (tabindex >= this.tabTitles.length) {
308         this.outOfBoundMessage(tabindex);
309         tabindex = 0;
310     }
311     //set old active tab to inactive
312     this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.tabStyles["fill"]);
313     if (this.hideContent) {
314         this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","none");
315     }
316     //set new index
317     this.activeTabindex = tabindex;
318     //activate new tab
319     this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.activetabBGColor);
320     //reorder tabs
321     this.tabGroup.appendChild(this.tabwindows[this.activeTabindex]["group"]);
322     //set display
323     if (this.hideContent) {
324         this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","inherit");
325     }
326     if (fireFunction) {
327         this.timer.setTimeout("fireFunction",this.timerMs);
328     }
331 tabgroup.prototype.activateTabByTitle = function(title,fireFunction) {
332     var tabindex = -1;
333     for (var i=0;i<this.tabTitles.length;i++) {
334         if (this.tabTitles[i] == title) {
335             tabindex = i;
336             break;
337         }
338     }
339     if (tabindex != -1) {
340         this.activateTabByIndex(tabindex,fireFunction);
341     }
342     else {
343         alert("Error ("+this.id+"): Could not find title '"+title+"' in array tabTitles!");
344     }
347 //add content to this.tabwindows[tabindex]["content"]
348 tabgroup.prototype.addContent = function(node,tabindex,inheritDisplay) {
349     if (tabindex >= this.tabTitles.length) {
350         this.outOfBoundMessage(tabindex);
351     }
352     else {
353         if (typeof(node) == "string") {
354             node = document.getElementById(node);
355         }
356         if (node != undefined || node != "null") {
357             if (inheritDisplay) {
358                 node.setAttributeNS(null,"display","inherit");
359             }
360             this.tabwindows[tabindex]["content"].appendChild(node);
361         }
362     }
365 //remove content from this.tabwindows[tabindex]["content"]
366 tabgroup.prototype.removeContent = function(node,tabindex) {
367     var deletedNode = undefined;
368     if (tabindex >= this.tabTitles.length) {
369         this.outOfBoundMessage(tabindex);
370     }
371     else {
372         if (typeof(node) == "string") {
373             node = document.getElementById(node);
374         }
375         if (node != undefined || node != "null") {
376             deletedNode = this.tabwindows[tabindex]["content"].removeChild(node);
377         }
378     }
379     return deletedNode;
382 //move the tab, reference is upper left corner
383 tabgroup.prototype.moveTo = function(x,y) {
384     this.transx = x;
385     this.transy = y;
386     this.tabGroup.setAttributeNS(null,"transform","translate("+this.transx+","+this.transy+")");
389 //resize tabgroup
390 tabgroup.prototype.resize = function(width,height) {
391     this.width = width;
392     this.height = height;
393     //loop to change all tab sizes
394     var currentX = this.x;
395     for (var i=0;i<this.tabTitles.length;i++) {
396         currentLeft = currentX;
397         //get bbox
398         var bbox = this.tabwindows[i]["tabTitle"].getBBox();
399         currentX = Math.round(currentLeft + this.tabmargins * 2 + bbox.width);
400         //start the path for tab windows
401         var d = "M";
402         //left corner of tab
403         if (this.cornerLeft == "rect") {
404             d += currentLeft+" "+this.y;
405         }
406         if (this.cornerLeft == "triangle") {
407             d += currentLeft+" "+(this.y+this.tabmargins)+"L"+(currentLeft+this.tabmargins)+" "+this.y;
408         }
409         if (this.cornerLeft == "round") {
410             d += currentLeft+" "+(this.y+this.tabmargins)+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" -"+this.tabmargins;
411         }
412         //right corner of tab
413         if (this.cornerRight == "rect") {
414             d += "L"+currentX+" "+this.y;
415         }
416         if (this.cornerRight == "triangle") {
417             d += "L"+(currentX-this.tabmargins)+" "+this.y+"L"+currentX+" "+(this.y+this.tabmargins);
418         }
419         if (this.cornerRight == "round") {
420             d += "L"+(currentX-this.tabmargins)+" "+this.y+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" "+this.tabmargins;
421         }
422         d += "L"+currentX+" "+(this.y+this.tabheight);
423         //complete the path for tab window
424         d += "L"+(this.x+this.width)+" "+(this.y+this.tabheight)+"L"+(this.x+this.width)+" "+(this.y+this.height);
425         d += "L"+this.x+" "+(this.y+this.height);
426         if (currentLeft == this.x) {
427             d += "z";
428         }
429         else {
430             d += "L"+this.x+" "+(this.y+this.tabheight)+"L"+currentLeft+" "+(this.y+this.tabheight)+"z";
431         }
432         //set modified path elements
433         this.tabwindows[i]["tabbg"].setAttributeNS(null,"d",d);
434         //increment currentX with the space between tabs
435         currentX += this.spaceBetweenTabs;
436     }
439 //deactivate a single tab
440 tabgroup.prototype.disableSingleTab = function(tabindex) {
441     if (tabindex >= this.tabTitles.length) {
442         this.outOfBoundMessage(tabindex);
443     }
444     else {
445         this.tabwindows[tabindex]["activeStatus"] = false;
446         if (!this.tabwindows[tabindex]["tabClone"]) {
447             this.tabwindows[tabindex]["tabClone"] = this.tabwindows[tabindex]["tab"].cloneNode(false);
448             this.tabwindows[tabindex]["tabClone"].removeEventListener("click",this,false);
449             this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"fill-opacity",0.5);
450             if (this.tabwindows[tabindex]["tabClone"].hasAttributeNS(null,"cursor")){
451                 this.tabwindows[tabindex]["tabClone"].removeAttributeNS(null,"cursor");
452             }
453             this.tabwindows[tabindex]["group"].appendChild(this.tabwindows[tabindex]["tabClone"]);
454         }
455         else {
456             this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"display","inherit");
457             this.tabwindows[tabindex]["group"].appendChild(this.tabwindows[tabindex]["tabClone"]);
458         }
459     }
462 //deactivate all tabs
463 tabgroup.prototype.disableAllTabs = function() {
464     for (var i=0;i<this.tabTitles.length;i++) {
465         this.disableSingleTab(i);
466     }
469 //deactivate all tabs
470 tabgroup.prototype.enableAllTabs = function() {
471     for (var i=0;i<this.tabTitles.length;i++) {
472         this.enableSingleTab(i);
473     }
476 //activate a single tab
477 tabgroup.prototype.enableSingleTab = function(tabindex) {
478     if (tabindex >= this.tabTitles.length) {
479         this.outOfBoundMessage(tabindex);
480     }
481     else {
482         this.tabwindows[tabindex]["activeStatus"] = true;
483         if (this.tabwindows[tabindex]["tabClone"]) {
484             this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"display","none");
485         }
486     }
489 //out of bound error message
490 tabgroup.prototype.outOfBoundMessage = function(tabindex) {
491     alert("Error ("+this.id+"): the 'tabindex' (value: "+tabindex+") is out of bounds!\nThe index nr is bigger than the number of tabs.");