chromium/third_party/blink/web_tests/svg/carto.net/resources/tabgroup.js

/*
Scripts to create interactive tabs in SVG using ECMA script
Copyright (C) <2006>  <Andreas Neumann>
Version 1.2, 2006-04-03
[email protected]
http://www.carto.net/
http://www.carto.net/neumann/

Credits:
* none so far

----

Documentation: http://www.carto.net/papers/svg/gui/tabgroup/

----

current version: 1.2.1

version history:
1.0 (2006-03-11)
initial version

1.1 (2006-04-03)
added ".moveTo(x,y)" and ".resize(width,height)" methods, added an additional g-element to hold transform values

1.2 (2006-06-19)
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
introduced id for group where content can be added, id name is: this.id+"__"+i+"_content"

1.2.1 (2006-07-07)
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

-------


This ECMA script library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library (lesser_gpl.txt); if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

----

original document site: http://www.carto.net/papers/svg/gui/tabgroup/
Please contact the author in case you want to use code or ideas commercially.
If you use this code, please include this copyright header, the included full
LGPL 2.1 text and read the terms provided in the LGPL 2.1 license
(http://www.gnu.org/copyleft/lesser.txt)

-------------------------------

Please report bugs and send improvements to [email protected]
If you use this control, please link to the original (http://www.carto.net/papers/svg/gui/tabgroup/)
somewhere in the source-code-comment or the "about" of your project and give credits, thanks!

*/

function tabgroup(id,parentNode,transx,transy,width,height,tabheight,cornerLeft,cornerRight,tabmargins,spaceBetweenTabs,tabStyles,activetabBGColor,tabwindowStyles,tabtextStyles,tabTitles,activeTabindex,hideContent,functionToCall) {
    var nrArguments = 19;
    var createTabgroup = true;
    if (arguments.length == nrArguments) {
        this.id = id;
        this.parentNode = parentNode; //can be of type string (id) or node reference (svg or g node)
        this.transx = transx;
        this.transy = transy;
        this.x = 0;
        this.y = 0;
        this.width = width;
        this.height = height;
        this.tabheight = tabheight;
        this.cornerLeft = cornerLeft; //values are "rect","round","triangle"
        this.cornerRight = cornerRight; //values are "rect","round","triangle"
        this.tabmargins = tabmargins;
        this.spaceBetweenTabs = spaceBetweenTabs;
        this.tabStyles = tabStyles;
        if (!this.tabStyles["fill"]) {
            this.tabStyles["fill"] = "lightgray";
        }
        this.activetabBGColor = activetabBGColor;
        this.tabwindowStyles = tabwindowStyles;
        this.tabtextStyles = tabtextStyles;
        if (!this.tabtextStyles["font-size"]) {
            this.tabtextStyles["font-size"] = 15;
        }
        this.tabTitles = tabTitles;
        if (this.tabTitles instanceof Array) {
            if (this.tabTitles.length == 0) {
                createTabgroup = false;
                alert("Error ("+this.id+"): the array 'tabTitles' has no elements!");
            }
        }
        else {
            createTabgroup = false;
            alert("Error ("+this.id+"): the array 'tabTitles' is not of type array!");
        }
        this.activeTabindex = activeTabindex;
        if (this.activeTabindex >= this.tabTitles.length) {
            createTabgroup = false;
            this.outOfBoundMessage(this.activeTabindex);
        }
        this.hideContent = hideContent; //boolean, defines whether the display of a tab should be set to "none","inherit"
        this.functionToCall = functionToCall;
        if (!(typeof(this.functionToCall) == "function" || typeof(this.functionToCall) == "object" || typeof(this.functionToCall) == "undefined")) {
            createTabgroup = false;
            alert("Error ("+this.id+"): functionToCall is of type '"+typeof(this.functionToCall)+"' and not of type 'function', 'object' or 'undefined'");
        }
    }
    else {
        createTabgroup = false;
        alert("Error ("+id+"): wrong nr of arguments! You have to pass over "+nrArguments+" parameters.");
    }
    if (createTabgroup) {
        this.parentGroup = null; //later a node reference to the parent group
        this.tabGroup = null; //later a reference to the group within the parentGroup
        this.tabwindows = new Array();
        this.timer = new Timer(this); //a Timer instance for calling the functionToCall
        this.timerMs = 200; //a constant of this object that is used in conjunction with the timer - functionToCall is called after 200 ms
        this.createTabGroup();
    }
    else {
        alert("Could not create tabgroup with id '"+this.id+"' due to errors in the constructor parameters");
    }
}

tabgroup.prototype.createTabGroup = function() {
    var result = this.testParent();
    if (result) {
    this.tabGroup = document.createElementNS(svgNS,"g");
    this.tabGroup.setAttributeNS(null,"transform","translate("+this.transx+","+this.transy+")");
    this.parentGroup.appendChild(this.tabGroup);
    //loop to create all tabs
    var currentX = this.x;
    for (var i=0;i<this.tabTitles.length;i++) {
        currentLeft = currentX;
        this.tabwindows[i] = new Array();
        //create group
        this.tabwindows[i]["group"] = document.createElementNS(svgNS,"g");
        this.tabGroup.appendChild(this.tabwindows[i]["group"]);
        //create tabTitle
        var tabtitles = this.tabTitles[i].split("\n");
        this.tabwindows[i]["tabTitle"] = document.createElementNS(svgNS,"text");
        this.tabwindows[i]["tabTitle"].setAttributeNS(null,"y",this.y + this.tabtextStyles["font-size"]);
        var value="";
        for (var attrib in this.tabtextStyles) {
            value = this.tabtextStyles[attrib];
            if (attrib == "font-size") {
                value += "px";
            }
            this.tabwindows[i]["tabTitle"].setAttributeNS(null,attrib,value);
        }
        this.tabwindows[i]["tabTitle"].setAttributeNS(null,"pointer-events","none");
        //create tspans and add text contents
        for (var j=0;j<tabtitles.length;j++) {
            var tspan = document.createElementNS(svgNS,"tspan");
            tspan.setAttributeNS(null,"x",currentX+this.tabmargins);
            var dy = this.tabtextStyles["font-size"]*1.1;
            if (j == 0) {
                dy = 0;
            }
            tspan.setAttributeNS(null,"dy",dy);
            var textNode = document.createTextNode(tabtitles[j]);
            tspan.appendChild(textNode);
            this.tabwindows[i]["tabTitle"].appendChild(tspan);
        }
        this.tabwindows[i]["group"].appendChild(this.tabwindows[i]["tabTitle"]);
        //get bbox
        var bbox = this.tabwindows[i]["tabTitle"].getBBox();
        currentX = Math.round(currentLeft + this.tabmargins * 2 + bbox.width);
        //check if text-anchor is middle and shift the x-values accordingly
        if (this.tabtextStyles["text-anchor"]) {
            if (this.tabtextStyles["text-anchor"] == "middle") {
                this.tabwindows[i]["tabTitle"].setAttributeNS(null,"transform","translate("+(bbox.width * 0.5)+" 0)");
            }
        }
        //now draw tabwindow background
        this.tabwindows[i]["tabbg"] = document.createElementNS(svgNS,"path");
        for (var attrib in this.tabwindowStyles) {
            this.tabwindows[i]["tabbg"].setAttributeNS(null,attrib,this.tabwindowStyles[attrib]);
        }
        //start the path for tab windows
        var d = "M";
        //left corner of tab
        if (this.cornerLeft == "rect") {
            d += currentLeft+" "+this.y;
        }
        if (this.cornerLeft == "triangle") {
            d += currentLeft+" "+(this.y+this.tabmargins)+"L"+(currentLeft+this.tabmargins)+" "+this.y;
        }
        if (this.cornerLeft == "round") {
            d += currentLeft+" "+(this.y+this.tabmargins)+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" -"+this.tabmargins;
        }
        //right corner of tab
        if (this.cornerRight == "rect") {
            d += "L"+currentX+" "+this.y;
        }
        if (this.cornerRight == "triangle") {
            d += "L"+(currentX-this.tabmargins)+" "+this.y+"L"+currentX+" "+(this.y+this.tabmargins);
        }
        if (this.cornerRight == "round") {
            d += "L"+(currentX-this.tabmargins)+" "+this.y+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" "+this.tabmargins;
        }
        d += "L"+currentX+" "+(this.y+this.tabheight);
        //complete the path for tab
        var dtab = d + "L"+currentLeft+" "+(this.y+this.tabheight)+"z";
        //complete the path for tab window
        d += "L"+(this.x+this.width)+" "+(this.y+this.tabheight)+"L"+(this.x+this.width)+" "+(this.y+this.height);
        d += "L"+this.x+" "+(this.y+this.height);
        if (currentLeft == this.x) {
            d += "z";
        }
        else {
            d += "L"+this.x+" "+(this.y+this.tabheight)+"L"+currentLeft+" "+(this.y+this.tabheight)+"z";
        }
        this.tabwindows[i]["tabbg"].setAttributeNS(null,"d",d);
        this.tabwindows[i]["group"].insertBefore(this.tabwindows[i]["tabbg"],this.tabwindows[i]["tabTitle"]);
        //create tab element
        this.tabwindows[i]["tab"] = document.createElementNS(svgNS,"path");
        for (var attrib in this.tabStyles) {
            this.tabwindows[i]["tab"].setAttributeNS(null,attrib,this.tabStyles[attrib]);
        }
        this.tabwindows[i]["tab"].setAttributeNS(null,"d",dtab);
        this.tabwindows[i]["tab"].setAttributeNS(null,"id",this.id+"__"+i);
        this.tabwindows[i]["tab"].addEventListener("click",this,false);
        this.tabwindows[i]["group"].insertBefore(this.tabwindows[i]["tab"],this.tabwindows[i]["tabTitle"]);
        //create group for tab content
        this.tabwindows[i]["content"] = document.createElementNS(svgNS,"g");
        this.tabwindows[i]["content"].setAttributeNS(null,"id",this.id+"__"+i+"_content");
        if (this.hideContent) {
            this.tabwindows[i]["content"].setAttributeNS(null,"display","none");
        }
        this.tabwindows[i]["group"].appendChild(this.tabwindows[i]["content"]);
        //set tab activate status
        this.tabwindows[i].activeStatus = true;
        //increment currentX with the space between tabs
        currentX += this.spaceBetweenTabs;
    }
    //activate one tab
    this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.activetabBGColor);
    this.tabGroup.appendChild(this.tabwindows[this.activeTabindex]["group"]);
    if (this.hideContent) {
        this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","inherit");
    }
    }
    else {
        alert("could not create or reference 'parentNode' of tabgroup with id '"+this.id+"'");
    }
 }
 
 //test if window group exists or create a new group at the end of the file
tabgroup.prototype.testParent = function() {
    //test if of type object
    var nodeValid = false;
    if (typeof(this.parentNode) == "object") {
        if (this.parentNode.nodeName == "svg" || this.parentNode.nodeName == "g") {
            this.parentGroup = this.parentNode;
            nodeValid = true;
        }
    }
    else if (typeof(this.parentNode) == "string") { 
        //first test if Windows group exists
        if (!document.getElementById(this.parentNode)) {
            this.parentGroup = document.createElementNS(svgNS,"g");
            this.parentGroup.setAttributeNS(null,"id",this.parentNode);
            document.documentElement.appendChild(this.parentGroup);
            nodeValid = true;
           }
           else {
               this.parentGroup = document.getElementById(this.parentNode);
               nodeValid = true;
           }
       }
       return nodeValid;
}

tabgroup.prototype.handleEvent = function(evt) {
    var tab = evt.target;
    var id = tab.getAttributeNS(null,"id");
    var idArray = id.split("__");
    var index = parseInt(idArray[1]);
    this.activateTabByIndex(index,false);
    //firefunction
    this.timer.setTimeout("fireFunction",this.timerMs);
}

tabgroup.prototype.fireFunction = function() {
    if (typeof(this.functionToCall) == "function") {
        this.functionToCall(this.id,this.tabTitles[this.activeTabindex],this.activeTabindex);
    }
    if (typeof(this.functionToCall) == "object") {
        this.functionToCall.tabActivated(this.id,this.tabTitles[this.activeTabindex],this.activeTabindex);
    }
    if (typeof(this.functionToCall) == undefined) {
        return;
    }
}

tabgroup.prototype.activateTabByIndex = function(tabindex,fireFunction) {
    if (tabindex >= this.tabTitles.length) {
        this.outOfBoundMessage(tabindex);
        tabindex = 0;
    }
    //set old active tab to inactive
    this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.tabStyles["fill"]);
    if (this.hideContent) {
        this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","none");
    }
    //set new index
    this.activeTabindex = tabindex;
    //activate new tab
    this.tabwindows[this.activeTabindex]["tab"].setAttributeNS(null,"fill",this.activetabBGColor);
    //reorder tabs
    this.tabGroup.appendChild(this.tabwindows[this.activeTabindex]["group"]);
    //set display
    if (this.hideContent) {
        this.tabwindows[this.activeTabindex]["content"].setAttributeNS(null,"display","inherit");
    }
    if (fireFunction) {
        this.timer.setTimeout("fireFunction",this.timerMs);
    }
}

tabgroup.prototype.activateTabByTitle = function(title,fireFunction) {
    var tabindex = -1;
    for (var i=0;i<this.tabTitles.length;i++) {
        if (this.tabTitles[i] == title) {
            tabindex = i;
            break;
        }
    }
    if (tabindex != -1) {
        this.activateTabByIndex(tabindex,fireFunction);
    }
    else {
        alert("Error ("+this.id+"): Could not find title '"+title+"' in array tabTitles!");
    }
}

//add content to this.tabwindows[tabindex]["content"]
tabgroup.prototype.addContent = function(node,tabindex,inheritDisplay) {
    if (tabindex >= this.tabTitles.length) {
        this.outOfBoundMessage(tabindex);
    }
    else {
        if (typeof(node) == "string") {
            node = document.getElementById(node);
        }
        if (node != undefined || node != "null") {
            if (inheritDisplay) {
                node.setAttributeNS(null,"display","inherit");
            }
            this.tabwindows[tabindex]["content"].appendChild(node);
        }
    }
}

//remove content from this.tabwindows[tabindex]["content"]
tabgroup.prototype.removeContent = function(node,tabindex) {
    var deletedNode = undefined;
    if (tabindex >= this.tabTitles.length) {
        this.outOfBoundMessage(tabindex);
    }
    else {
        if (typeof(node) == "string") {
            node = document.getElementById(node);
        }
        if (node != undefined || node != "null") {
            deletedNode = this.tabwindows[tabindex]["content"].removeChild(node);
        }
    }
    return deletedNode;
}

//move the tab, reference is upper left corner
tabgroup.prototype.moveTo = function(x,y) {
    this.transx = x;
    this.transy = y;
    this.tabGroup.setAttributeNS(null,"transform","translate("+this.transx+","+this.transy+")");
}

//resize tabgroup
tabgroup.prototype.resize = function(width,height) {
    this.width = width;
    this.height = height;
    //loop to change all tab sizes
    var currentX = this.x;
    for (var i=0;i<this.tabTitles.length;i++) {
        currentLeft = currentX;
        //get bbox
        var bbox = this.tabwindows[i]["tabTitle"].getBBox();
        currentX = Math.round(currentLeft + this.tabmargins * 2 + bbox.width);
        //start the path for tab windows
        var d = "M";
        //left corner of tab
        if (this.cornerLeft == "rect") {
            d += currentLeft+" "+this.y;
        }
        if (this.cornerLeft == "triangle") {
            d += currentLeft+" "+(this.y+this.tabmargins)+"L"+(currentLeft+this.tabmargins)+" "+this.y;
        }
        if (this.cornerLeft == "round") {
            d += currentLeft+" "+(this.y+this.tabmargins)+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" -"+this.tabmargins;
        }
        //right corner of tab
        if (this.cornerRight == "rect") {
            d += "L"+currentX+" "+this.y;
        }
        if (this.cornerRight == "triangle") {
            d += "L"+(currentX-this.tabmargins)+" "+this.y+"L"+currentX+" "+(this.y+this.tabmargins);
        }
        if (this.cornerRight == "round") {
            d += "L"+(currentX-this.tabmargins)+" "+this.y+"a"+this.tabmargins+" "+this.tabmargins+" 0 0 1 "+this.tabmargins+" "+this.tabmargins;
        }
        d += "L"+currentX+" "+(this.y+this.tabheight);
        //complete the path for tab window
        d += "L"+(this.x+this.width)+" "+(this.y+this.tabheight)+"L"+(this.x+this.width)+" "+(this.y+this.height);
        d += "L"+this.x+" "+(this.y+this.height);
        if (currentLeft == this.x) {
            d += "z";
        }
        else {
            d += "L"+this.x+" "+(this.y+this.tabheight)+"L"+currentLeft+" "+(this.y+this.tabheight)+"z";
        }
        //set modified path elements
        this.tabwindows[i]["tabbg"].setAttributeNS(null,"d",d);
        //increment currentX with the space between tabs
        currentX += this.spaceBetweenTabs;
    }
}

//deactivate a single tab
tabgroup.prototype.disableSingleTab = function(tabindex) {
    if (tabindex >= this.tabTitles.length) {
        this.outOfBoundMessage(tabindex);
    }
    else {
        this.tabwindows[tabindex]["activeStatus"] = false;
        if (!this.tabwindows[tabindex]["tabClone"]) {
            this.tabwindows[tabindex]["tabClone"] = this.tabwindows[tabindex]["tab"].cloneNode(false);
            this.tabwindows[tabindex]["tabClone"].removeEventListener("click",this,false);
            this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"fill-opacity",0.5);
            if (this.tabwindows[tabindex]["tabClone"].hasAttributeNS(null,"cursor")){
                this.tabwindows[tabindex]["tabClone"].removeAttributeNS(null,"cursor");
            }
            this.tabwindows[tabindex]["group"].appendChild(this.tabwindows[tabindex]["tabClone"]);
        }
        else {
            this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"display","inherit");
            this.tabwindows[tabindex]["group"].appendChild(this.tabwindows[tabindex]["tabClone"]);
        }
    }
}

//deactivate all tabs
tabgroup.prototype.disableAllTabs = function() {
    for (var i=0;i<this.tabTitles.length;i++) {
        this.disableSingleTab(i);
    }
}

//deactivate all tabs
tabgroup.prototype.enableAllTabs = function() {
    for (var i=0;i<this.tabTitles.length;i++) {
        this.enableSingleTab(i);
    }
}

//activate a single tab
tabgroup.prototype.enableSingleTab = function(tabindex) {
    if (tabindex >= this.tabTitles.length) {
        this.outOfBoundMessage(tabindex);
    }
    else {
        this.tabwindows[tabindex]["activeStatus"] = true;
        if (this.tabwindows[tabindex]["tabClone"]) {
            this.tabwindows[tabindex]["tabClone"].setAttributeNS(null,"display","none");
        }
    }
}

//out of bound error message
tabgroup.prototype.outOfBoundMessage = function(tabindex) {
    alert("Error ("+this.id+"): the 'tabindex' (value: "+tabindex+") is out of bounds!\nThe index nr is bigger than the number of tabs.");
}