def get_onload_js(self):
    return '\n\nif (spt.tab) {\n    return;\n}\n\nspt.Environment.get().add_library("spt_tab");\n\n\nspt.tab = {};\n\nspt.tab.top = null;\n\nspt.tab.set_main_body_tab = function() {\n    spt.tab.top = document.id(document.body).getElement(".spt_tab_top");\n    return spt.tab.top;\n}\n\n// this is to be deprecated\nspt.tab.set_main_body_top = function() {\n    spt.tab.top = document.id(\'main_body\').getElement(".spt_tab_top");\n}\n\n\nspt.tab.set_tab_top = function( tab_top ) {\n    // if this is not really a tab top, then find a child\n    if (! tab_top.hasClass("spt_tab_top") ) {\n        tab_top = tab_top.getElement(".spt_tab_top");\n    }\n    spt.tab.top = tab_top;\n    return spt.tab.top;\n}\n\n\nspt.tab.set_tab_top_from_child = function( el ) {\n    // if this is not really a tab top, then find a parent\n    if (! el.hasClass("spt_tab_top") ) {\n        el = el.getParent(".spt_tab_top");\n    }\n    \n    \n    spt.tab.top = el;\n    return spt.tab.top;\n}\n\n\nspt.tab.get_headers = function() {\n    var top = spt.tab.top;\n    var tab_id = top.getAttribute("id");\n\n    var header_top = top.getElement(".spt_tab_header_top");\n    var all_headers = header_top.getElements(".spt_tab_header");\n    //return all_headers;\n\n    var headers = [];\n    for (var i = 0; i < all_headers.length; i++ ) {\n        var header_tab_id = all_headers[i].getAttribute("spt_tab_id");\n        if (header_tab_id != tab_id) {\n            continue;\n        }\n\n        headers.push(all_headers[i]);\n    }\n\n    return headers;\n}\n\n\nspt.tab.get_header = function(name) {\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = header_top.getElements(".spt_tab_header");\n    for (var i = 0; i < headers.length; i++) {\n        if (name == headers[i].getAttribute("spt_element_name") ) {\n            return headers[i];\n        }\n    }\n    return null;\n}\n\n\n\n\nspt.tab.resize_headers = function() {\n\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n\n    var offset = 120;\n\n    var size = top.getSize();\n    top.spt_last_width = size.x;\n\n    var els = header_top.getElements(".spt_tab_header");\n    var count = els.length;\n\n    var width = parseInt((size.x-offset) / (count));\n    if (width > 120) {\n        width = 120;\n    }\n    if (width < 30) {\n        width = 30;\n    }\n\n    for (var i = 0; i < els.length; i++) {\n        els[i].setStyle("width", width + \'px\');\n        //var title_el = els[i].getElement(".spt_tab_header_label");\n        els[i].setStyle("width", width + \'px\');\n    }\n}\n\n\n\n\n\nspt.tab.get_content = function(name) {\n    var top = spt.tab.top;\n    var tab_id = top.getAttribute("spt_tab_id");\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var all_contents = content_top.getElements(".spt_tab_content");\n\n    // FIXME: this breaks when opening new tabs for some reason\n    //return all_contents;\n\n    for (var i = 0; i < all_contents.length; i++ ) {\n        var content_tab_id = all_contents[i].getAttribute("spt_tab_id");\n        var content_name = all_contents[i].getAttribute("spt_element_name");\n        if (content_name == name) {\n            return all_contents[i];\n        }\n    }\n\n\n    return null;\n}\n\n\n\n\n\nspt.tab.get_contents = function() {\n    var top = spt.tab.top;\n    var tab_id = top.getAttribute("spt_tab_id");\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var all_contents = content_top.getElements(".spt_tab_content");\n\n    // FIXME: this breaks when opening new tabs for some reason\n    //return all_contents;\n\n    var contents = [];\n    for (var i = 0; i < all_contents.length; i++ ) {\n        var content_tab_id = all_contents[i].getAttribute("spt_tab_id");\n        if (content_tab_id == null) {\n            alert(all_contents[i].getAttribute("spt_element_name"));\n        }\n        if (content_tab_id != tab_id) {\n            continue;\n        }\n\n        contents.push(all_contents[i]);\n    }\n\n\n    return contents;\n}\n\n\n\n\nspt.tab.set_attribute = function(element_name, name, value) {\n    var header = spt.tab.get_header(element_name);\n    var kwargs_str = header.getAttribute("spt_kwargs");\n    var kwargs;\n    if (kwargs_str != \'\') {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\')\n        kwargs = JSON.parse(kwargs_str);\n    }\n    else {\n        kwargs = {};\n    }\n\n    kwargs[name] = value;\n    header.setAttribute("spt_"+name, value);\n\n    kwargs_str = JSON.stringify(kwargs);\n    kwargs_str = kwargs_str.replace(/"/g,"\\&amp;quot\\;");\n    header.setAttribute("spt_kwargs", kwargs_str);\n\n}\n\n\n\n\n\nspt.tab.add_new = function(element_name, title, class_name, kwargs,\n        values, hash) {\n\n    if (typeof(title) == \'undefined\') {\n        title = \'(Untitled)\';\n    }\n    if (typeof(element_name) == \'undefined\') {\n        //alert("No element name provided");\n        //return;\n        element_name = "__default__";\n    }\n    if (typeof(class_name) == \'undefined\') {\n        class_name = \'\';\n    }\n    if (typeof(kwargs) == \'undefined\') {\n        kwargs = {};\n    }\n    if (typeof(values) == \'undefined\') {\n        values = {};\n    }\n\n    var top = spt.tab.top;\n    if (!top) {\n        spt.tab.set_main_body_tab();\n        top = spt.tab.top;\n    }\n\n    if (!hash && hash != false && kwargs.hash) {\n        hash = kwargs.hash;\n    }\n    if (hash == "__link__") {\n        hash = "link/" + element_name;\n    }\n\n\n    var orig_element_name = element_name;\n\n    var mode = top.getAttribute("spt_tab_mode");\n    if (mode == "hidden") {\n        element_name = "__default__";\n    }\n\n    var unique = kwargs.unique;\n    if (unique == true || unique == "true") {\n        var header = spt.tab.get_header(element_name);\n        if (header) {\n            var num = Math.floor((Math.random()*10000)+1); \n            element_name = element_name + num;\n        }\n    }\n\n\n    var top_id = top.getAttribute("spt_tab_id");\n\n    // disable sub tabs for now\n    full_element_name = element_name;\n    subelement_name = "";\n    /*\n    if (element_name.indexOf("/") != -1) {\n        var full_element_name = element_name;\n        var parts = element_name.split("/");\n        element_name = parts[0];\n        var subelement_name = parts[1];\n    }\n    else {\n        var full_element_name = element_name;\n        var subelement_name = "";\n    }\n    */\n\n\n    var subelement_title;\n    var full_title;\n    if (title.indexOf("/") != -1) {\n        full_title = title;\n        var parts = title.split("/");\n        title = parts[0];\n        subelement_title = parts[1];\n    }\n    else {\n        full_title = title;\n        subelement_title = title;\n    }\n\n   \n    //var headers = header_top.getElements(".spt_tab_header");\n    var headers = spt.tab.get_headers();\n\n    if (headers.length > 20) {\n        spt.alert("You have too many tabs open. Please close before opening any others.");\n        return;\n    }\n\n    var header;\n    var found = false;\n    for (var k=0; k < headers.length; k++){\n        var existing_header = headers[k];\n        if (existing_header.getAttribute(\'spt_element_name\')==element_name){\n            header = existing_header;\n            found = true;\n            break;\n        }\n    }\n\n    // add a new tab\n    if (!found) {\n        var template_top = top.getElement(".spt_tab_template_top");\n        var header_template = template_top.getElement(".spt_tab_header");\n\n        // clone the header template\n        var header = spt.behavior.clone(header_template);\n        var header_id = Math.floor(Math.random()*10000000+1);\n        header.setAttribute("id", header_id);\n\n        if (kwargs.hidden == "true") {\n            header.setStyle("display", "none");\n        }\n\n\n        // add a subheader template for each header\n        var subheader_template = template_top.getElement(".spt_tab_subheader");\n        if (subheader_template) {\n            var subheader = spt.behavior.clone(subheader_template);\n\n            var subheader_id = Math.floor(Math.random()*10000000+1);\n            header.setAttribute("spt_subheader_id", subheader_id);\n\n            subheader.setAttribute("id", subheader_id);\n            subheader.setStyle("display", "none");\n\n            subheader.setAttribute("spt_header_id", header_id);\n\n            subheader_top = top.getElement(".spt_tab_subheader_top")\n            subheader.inject(subheader_top);\n        }\n       \n\n        var last_header = headers[headers.length -1];\n\n        // set the new label\n        var label = header.getElement(".spt_tab_header_label");\n        var display_title = title;\n\n        label.setAttribute("title", title);\n        label.innerHTML = display_title;\n\n        header.setAttribute("spt_class_name", class_name);\n        var kwargs_str = JSON.stringify(kwargs);\n        kwargs_str = kwargs_str.replace(/\\"/,"\\&amp;quot\\;");\n        header.setAttribute("spt_kwargs", kwargs_str);\n        header.setAttribute("spt_element_name", element_name);\n        header.setAttribute("spt_title", title);\n        header.setAttribute("spt_tab_id", top_id);\n        header.removeClass("spt_content_loaded");\n        header.inject(last_header, "after");\n\n        spt.tab.resize_headers();\n\n\n        var selected_header = spt.tab.get_selected_header();\n        if (selected_header) {\n            var opener = selected_header.getAttribute("spt_element_name");\n            header.setAttribute("spt_tab_opener", opener);\n        }\n\n        // copy the content from template\n        var content_top = top.getElement(".spt_tab_content_top");\n        var content_template = template_top.getElement(".spt_tab_content");\n        var content_box = spt.behavior.clone(content_template);\n\n        content_box.setAttribute("spt_element_name", element_name);\n        content_box.setAttribute("spt_title", title);\n        content_box.setAttribute("spt_tab_id", top_id);\n\n        var content_boxes = spt.tab.get_contents();\n        var last_content = content_boxes[content_boxes.length -1];\n        content_box.inject(last_content, "after");\n\n        if (kwargs.count) {\n            var count_div = header.getElement(".spt_tab_header_count");\n\n            var expression = kwargs.count;\n            var search_key = kwargs.search_key;\n\n            var server = TacticServerStub.get();\n            var count = server.eval(expression, {search_keys: search_key});\n\n            count_div.innerText = count;\n\n            var update_data = {\n                expression: expression,\n                expr_key: search_key\n            };\n\n            spt.update.add(count_div, update_data);\n        }\n\n    }\n\n\n    // if a subtab is needed, create that\n    if (subelement_name) {\n        // find out if the subheader exists\n        var subheader_id = header.getAttribute("spt_subheader_id");\n        var subheader_top = document.id(subheader_id);\n        var subheaders = subheader_top.getElements(".spt_tab_subheader_item");\n\n        var subheader_exists = false;\n        var subheader = null;\n        for (var i = 0; i < subheaders.length; i++) {\n            var box_name = subheaders[i].getAttribute("spt_element_name");\n            if (full_element_name == box_name) {\n                subheader_exists = true;\n                subheader = subheaders[i];\n                break;\n            }\n        }\n\n        if (subheader_exists == false) {\n\n            // create a new one\n            var subheader = document.id(document.createElement("div"));\n            subheader.innerHTML = "<div style=\'padding: 5px 5px\'><div class=\'spt_tab_header_label\'>"+subelement_name+"</div></div>";\n            subheader_top.appendChild(subheader);\n            subheader.addClass("spt_tab_subheader_item");\n\n\n            // set the new label\n            var label = subheader.getElement(".spt_tab_header_label");\n            var display_title = subelement_title;\n            if (display_title.length > 20) {\n                display_title = subelement_title.substr(0,18) + "...";\n            }\n            title = subelement_name;\n\n            label.setAttribute("title", subelement_title);\n            label.innerHTML = display_title;\n\n            subheader.setAttribute("spt_class_name", class_name);\n            var kwargs_str = JSON.stringify(kwargs);\n            kwargs_str = kwargs_str.replace(/\\"/,"\\&amp;quot\\;");\n            subheader.setAttribute("spt_kwargs", kwargs_str);\n            subheader.setAttribute("spt_element_name", full_element_name);\n            subheader.setAttribute("spt_title", full_title);\n            subheader.setAttribute("spt_tab_id", top_id);\n            subheader.removeClass("spt_content_loaded");\n\n\n            // copy the content from template\n            var template_top = top.getElement(".spt_tab_template_top");\n            var content_top = top.getElement(".spt_tab_content_top");\n            var content_template = template_top.getElement(".spt_tab_content");\n            var content_box = spt.behavior.clone(content_template);\n\n            content_box.setAttribute("spt_element_name", full_element_name);\n            content_box.setAttribute("spt_title", full_title);\n            content_box.setAttribute("spt_tab_id", top_id);\n\n            var content_boxes = spt.tab.get_contents();\n            var last_content = content_boxes[content_boxes.length -1];\n            content_box.inject(last_content, "after");\n\n\n        }\n\n    }\n\n\n    if (! class_name) {\n        spt.tab.select(element_name);\n    }\n    else if (subelement_name) {\n        var force = true;\n        spt.tab.load_class(subheader, class_name, kwargs, values, force);\n    }\n    else {\n        var force = true;\n        spt.tab.load_class(header, class_name, kwargs, values, force);\n    }\n\n    // FIXME: this should only move on the main table\n    //var top_pos = spt.tab.getY(header_top);\n    //scroll(0,top_pos-20);\n\n\n    // register the hash\n    if (hash) {\n        var state = {\n            element_name: orig_element_name,\n            title: title,\n            class_name: class_name,\n            kwargs: kwargs,\n            hash: hash,\n            mode: \'tab\',\n        }\n        spt.hash.set_hash(state, title, hash);\n    }\n\n    if (top.hasClass("spt_tab_save_state") ) {\n        spt.tab.save_state();\n    }\n\n\n    return header;\n}\n\n// TEST\nspt.tab.getY = function(oElement)\n{\n    var iReturnValue = 0;\n        while( oElement != null ) {\n        iReturnValue += oElement.offsetTop;\n        oElement = oElement.offsetParent;\n    }\n    return iReturnValue;\n}\n\n\n\nspt.tab.load_selected = function(element_name, title, class_name, kwargs, values) {\n    var top = spt.tab.top;\n\n\n    var header = spt.tab.get_selected_header();\n    // if none are selected, use the last one\n    if (header == null) {\n        var headers = spt.tab.get_headers();\n        header = headers[headers.length - 1];\n    }\n\n    var old_element_name = header.getAttribute("spt_element_name");\n\n    header.setAttribute("spt_element_name", element_name);\n    header.setAttribute("spt_title", title);\n    header.setAttribute("spt_class_name", class_name);\n\n    if (typeof(kwargs) == \'undefined\') {\n        kwargs = {};\n    }\n    var kwargs_str = JSON.stringify(kwargs)\n    header.setAttribute("spt_kwargs", kwargs_str);\n\n    var label = header.getElement(".spt_tab_header_label");\n    var display_title = title;\n    if (display_title.length > 20) {\n        display_title = title.substr(0,18) + "...";\n    }\n    label.innerHTML = display_title;\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = content_top.getElements(".spt_tab_content");\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == old_element_name) {\n            content_box.setAttribute("spt_element_name", element_name)\n            break;\n        }\n    }\n    \n \n    var force = true; \n    spt.tab.load_class(header, class_name, kwargs, values, force);\n}\n\n\n\n// add a DOM node to the named content\nspt.tab.load_node = function(element_name, node) {\n    var top = spt.tab.top;\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = spt.tab.get_contents();\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == element_name) {\n\n            if(content_box.hasChildNodes()) {\n                while(content_box.childNodes.length >= 1 ) {\n                    content_box.removeChild(content_box.firstChild);\n                }\n            }\n\n            content_box.appendChild(node);\n\n\n            break;\n        }\n    }\n\n}    \n\n// add raw HTML to the named content\nspt.tab.load_html = function(element_name, html) {\n    var top = spt.tab.top;\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = spt.tab.get_contents();\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == element_name) {\n           spt.behavior.replace_inner_html(content_box, html);\n        }\n    }\n\n}    \n \n\n\n\nspt.tab.select = function(element_name) {\n\n    var header = spt.tab.get_header(element_name);\n    var top = spt.tab.top;\n\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = spt.tab.get_headers();\n    for (var i=0; i < headers.length; i++) {\n        headers[i].setStyle("opacity", "0.4");\n        headers[i].setStyle("font-weight", "normal");\n        headers[i].removeClass("spt_is_selected");\n        headers[i].removeClass("spt_tab_selected");\n        headers[i].addClass("spt_tab_unselected");\n    }\n    if (header) {\n        header.setStyle("opacity", "1.0");\n        header.addClass("spt_is_selected");\n        header.addClass("spt_tab_selected");\n        header.removeClass("spt_tab_unselected");\n    }\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = spt.tab.get_contents();\n\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        content_box.setStyle("display", "none");\n    }\n\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == element_name) {\n            content_box.setStyle("display", "");\n            if (!content_box.hasClass("spt_content_loaded")) {\n                spt.tab.load_class(header);\n            }\n            break;\n        }\n    }\n\n\n    var kwargs_str = header ? header.getAttribute("spt_kwargs") : \'\';\n    if (!kwargs_str) {\n        kwargs = {};\n    }\n    else {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n        kwargs = JSON.parse(kwargs_str);\n    }\n\n    bvr.options = {\n      element_name: element_name,\n      alias: kwargs.help_alias\n    }\n    spt.named_events.fire_event("tab|select", bvr);\n    \n    // usually a tab contains a table and layout. it\'s better to set to that.\n    var tab_content = top.getElement(\'.spt_tab_content[spt_element_name=\' + element_name + \']\');\n    if (tab_content) {\n        var table = tab_content.getElement(\'.spt_table_table\');\n        if (table) {\n            var layout = table.getParent(".spt_layout");\n            spt.table.set_layout(layout);\n        }\n\n        var last_element_name = spt.tab.get_selected_element_name();\n        if (last_element_name) {\n            top.setAttribute("spt_last_element_name", last_element_name);\n        }\n\n        return true;\n    } else {\n\n        return false;\n    }\n\n\n}\n\n\n\nspt.tab.load_class = function(header, class_name, kwargs, values, force) {\n    var title = header.getAttribute("spt_title");\n    var tab_element_name = header.getAttribute("spt_element_name");\n\n    if (typeof(force) == \'undefined\') {\n         force = false;\n    }\n\n    if (typeof(class_name) == \'undefined\') {\n        var class_name = header.getAttribute("SPT_WIDGET_KEY");\n        if (! class_name) {\n            class_name = header.getAttribute("spt_class_name");\n        }\n    }\n\n    if (typeof(kwargs) == \'undefined\') {\n        kwargs = {};\n        var kwargs_str = header.getAttribute("spt_kwargs");\n        if (kwargs_str) {\n            kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n            kwargs = JSON.parse(kwargs_str);\n        } \n    }\n\n\n\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n    var top_id = top.getAttribute("id");\n\n    //spt.api.app_busy_show("Loading " + title, \'\');\n\n    setTimeout( function() {\n\n        var header_top = header.getParent(".spt_tab_header_top");\n        var headers = spt.tab.get_headers();\n        for (var i=0; i < headers.length; i++) {\n            headers[i].setStyle("opacity", "0.4");\n            headers[i].setStyle("font-weight", "normal");\n            headers[i].removeClass("spt_is_selected");\n            headers[i].removeClass("spt_tab_selected");\n            headers[i].addClass("spt_tab_unselected");\n        }\n\n\n        // select the header\n        if (header.hasClass("spt_tab_subheader_item")) {\n            var subheader_top = header.getParent(".spt_tab_subheader");\n            header_id = subheader_top.getAttribute("spt_header_id");\n            select_header = document.id(header_id);\n        }\n        else {\n            select_header = header;\n        }\n\n        // select the header\n        select_header.setStyle("opacity", "1.0");\n        select_header.addClass("spt_is_selected");\n        select_header.addClass("spt_tab_selected");\n        select_header.removeClass("spt_tab_unselected");\n\n\n\n\n        var content_top = top.getElement(".spt_tab_content_top");\n        var content_boxes = spt.tab.get_contents();\n\n        // make all of the content boxes disappear\n        for (var i=0; i < content_boxes.length; i++) {\n            var content_box = content_boxes[i];\n            content_box.setStyle("display", "none");\n        }\n\n        for (var i=0; i < content_boxes.length; i++) {\n\n            var content_box = content_boxes[i];\n            var box_name = content_box.getAttribute("spt_element_name")\n            if (box_name == tab_element_name) {\n                content_box.setStyle("display", "");\n\n                // if no class name is defined, then break out\n                if (typeof(class_name) == \'undefined\' || class_name == \'\') {\n                    break;\n                }\n\n                if (force || ! content_box.hasClass("spt_content_loaded")) {\n\n                    var resize_offset = content_box.getAttribute("spt_window_resize_offset");\n\n                    spt.panel.load(content_box, class_name, kwargs, values);\n\n                    // update info on header\n                    header.setAttribute("spt_class_name", class_name);\n                    var kwargs_str = JSON.stringify(kwargs);\n                    kwargs_str = kwargs_str.replace(/\\"/,"\\&amp;quot\\;");\n                    header.setAttribute("spt_kwargs", kwargs_str);\n                    header.setAttribute("spt_element_name", tab_element_name);\n                    header.setAttribute("spt_title", title);\n\n                    content_box.addClass("spt_content_loaded");\n                    // have to set this again because load removes it\n                    content_box.setAttribute("spt_element_name", tab_element_name);\n                    content_box.setAttribute("spt_tab_id", top_id);\n                    content_box.setAttribute("spt_title", title);\n\n                    if (resize_offset) {\n                        content_box.setAttribute("spt_window_resize_offset", resize_offset);\n                    }\n\n                }\n                break;\n            }\n        }\n\n        var bvr = {};\n        var parts = tab_element_name.split("/");\n        var element_name = parts[parts.length-1];\n\n        var alias = kwargs.help_alias;\n        bvr.options = {\n          element_name: element_name,\n          alias: alias\n        }\n        spt.named_events.fire_event("tab|select", bvr);\n        spt.api.app_busy_hide();\n\n      }, 10 );\n\n    \n}\n\n\nspt.tab.reload_selected = function() {\n    var header = spt.tab.get_selected_header();\n    var class_name = header.getAttribute("spt_class_name");\n    var kwargs = header.getAttribute("spt_kwargs");\n\n    var kwargs_str = header.getAttribute("spt_kwargs");\n    var kwargs;\n    if (kwargs_str != \'\') {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n        kwargs = JSON.parse(kwargs_str);\n    }\n    else {\n        kwargs = {};\n    }\n\n    var values = null;\n    var force = true;\n    spt.tab.load_class(header, class_name, kwargs, values, force);\n}\n\n\n\nspt.tab.get_selected_header = function() {\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = header_top.getElements(".spt_tab_header");\n    for (var i = 0; i < headers.length; i++) {\n        var header = headers[i];\n        if ( header.hasClass("spt_is_selected") ) {\n            return header;\n        }\n        \n    }\n    return null;\n}\n\n\nspt.tab.get_selected_element_name = function() {\n    var header = spt.tab.get_selected_header();\n    if (header) {\n        var element_name = header.getAttribute("spt_element_name");\n        return element_name;\n    }\n    return "";\n}\n\n\nspt.tab.get_last_selected_element_name = function() {\n    var top = spt.tab.top;\n    return top.getAttribute("spt_last_element_name");\n}\n\n\nspt.tab.save_state = function() {\n    var top = spt.tab.top;\n    var save_state = top.getAttribute("spt_tab_save_state");\n\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = header_top.getElements(".spt_tab_header");\n\n    var class_names = [];\n    var attrs_list = [];\n    var kwargs_list = [];\n    for (var i = 0; i < headers.length; i++) {\n        var header = headers[i];\n\n        var element_name = header.getAttribute("spt_element_name")\n        var title = header.getAttribute("spt_title")\n        var attrs = {\n            name: element_name,\n            title: title\n        };\n        \n\n        var class_name = header.getAttribute("spt_class_name");\n        class_names.push(class_name);\n        var kwargs_str = header.getAttribute("spt_kwargs");\n\n        var kwargs;\n        if (kwargs_str) {\n            kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n            kwargs = JSON.parse(kwargs_str);\n        }\n        else {\n            kwargs = {};\n        }\n        kwargs_list.push(kwargs);\n\n        if (kwargs.count)\n            attrs.count = kwargs.count;\n        attrs_list.push(attrs)\n    }\n\n    var server = TacticServerStub.get();\n    var command = \'tactic.ui.container.TabSaveStateCmd\';\n    var kwargs = {\n        class_names: class_names,\n        attrs_list: attrs_list,\n        kwargs_list: kwargs_list,\n        save_state: save_state\n    };\n    server.execute_cmd(command, kwargs, {}, { \n        on_complete: function(ret_val) {console.log(ret_val)}, \n        on_error: function(err) {console.log(err)} \n    });\n\n}\n\n\n\n\nspt.tab.header_pos = null;\nspt.tab.mouse_pos = null;\nspt.tab.dragging = false;\n\nspt.tab.header_drag_setup = function( evt, bvr, mouse_411) {\n    spt.tab.top = bvr.src_el.getParent(".spt_tab_top");\n    spt.tab.header_pos = bvr.src_el.getPosition(spt.tab.top);\n    spt.tab.mouse_pos = {x: mouse_411.curr_x, y: mouse_411.curr_y};\n    var header = bvr.src_el;\n    var element_name = header.getAttribute("spt_element_name");\n    spt.tab.select(element_name);\n}\n\nspt.tab.header_drag_motion = function( evt, bvr, mouse_411) {\n    //var header = bvr.drag_el;\n    var header = bvr.src_el;\n    var dx = mouse_411.curr_x - spt.tab.mouse_pos.x;\n    var dy = mouse_411.curr_y - spt.tab.mouse_pos.y;\n    if (Math.abs(dx) < 20) {\n        spt.tab.dragging = false;\n        return;\n    }\n    spt.tab.dragging = true;\n    header.setStyle("position", "absolute");\n    header.setStyle("z-index", "100");\n    header.setStyle("opacity", "1.0");\n\n    header.setStyle("left", spt.tab.header_pos.x + dx - 10 );\n    //header.setStyle("top", spt.tab.header_pos.y + dy );\n}\n\nspt.tab.header_drag_action = function( evt, bvr, mouse_411) {\n    var header = bvr.src_el;\n    var drag_pos = header.getPosition();\n    if (spt.tab.dragging == false)\n        return;\n\n    \n    var headers = spt.tab.get_headers();\n    for ( var i = headers.length-1; i >= 0; i-- ) {\n        if (headers[i] == header) {\n            continue;\n        }\n\n        if (headers[i].getStyle("display") == "none") {\n            continue;\n        }\n\n        var pos = headers[i].getPosition();\n\n        var size = headers[i].getSize();\n        // the y ensures 2nd row tabs don\'t jump to first row on click\n        if (drag_pos.x > pos.x + size.x/2 && drag_pos.y >= pos.y) {\n            header.inject(headers[i], "after");\n            break;\n        }\n        if (drag_pos.x > pos.x && drag_pos.y >= pos.y ) {\n            header.inject(headers[i], "before");\n            break;\n        }\n\n\n\n    }\n\n    bvr.drag_el.setStyle("position", "relative");\n    bvr.drag_el.setStyle("z-index", "");\n    bvr.drag_el.setStyle("top", "");\n    bvr.drag_el.setStyle("left", "");\n\n    bvr.drag_el.setStyle("background", bvr.gradient);\n\n    var top = spt.tab.top;\n    if (top.hasClass("spt_tab_save_state") ) {\n        spt.tab.save_state();\n    }\n\n}\n\n\nspt.tab.close = function(src_el) {\n    // src_el should be a child of spt_tab_content or spt_tab_header\n    if (!src_el) {\n        spt.error(\'src_el passed in to spt.tab.close() does not exist.\');\n        return;\n    }\n    spt.tab.top = src_el.getParent(".spt_tab_top");\n    \n    var top = spt.tab.top;\n    var headers = spt.tab.get_headers();\n    if (headers.length == 1) {\n        return;\n    }\n\n\n    var content = src_el.getParent(".spt_tab_content");\n    var element_name;\n    // check if it\'s a header child\n    if (src_el.hasClass("spt_tab_header")) {\n        var header = src_el;\n    }\n    else {\n        var header = src_el.getParent(".spt_tab_header");\n    }\n    var subheader = src_el.getParent(".spt_tab_subheader");\n    if (header) {\n        element_name = header.getAttribute("spt_element_name");\n        content = spt.tab.get_content(element_name);\n    } else if (subheader) {\n        element_name = header.getAttribute("spt_element_name");\n        content = spt.tab.get_content(element_name);\n    } else if (content) {\n        element_name = content.getAttribute("spt_element_name");\n        header = spt.tab.get_selected_header(element_name);\n    } \n\n    if (!header || !content) {\n        spt.error(\'Tab close cannot find the header or content. Abort\');\n        return;\n    }\n\n    \n    /* If there are changed elements in the current tab, changedParameters\n     * is a list with index 0 containing changed element, and index 1 containing\n     * change type class. Otherwise, changedParameters is false. \n     */\n    function ok(changedParameters) {\n        //Remove unsaved changes flags\n        if (changedParameters) {\n            var changed_element = changedParameters[0];\n            var changed_type = changedParameters[1];\n            changed_element.removeClass(changed_type);\n        }\n        var opener = header.getAttribute("spt_tab_opener");\n        var element_name = header.getAttribute("spt_element_name");\n\n        if (header) {\n            var subheader = document.id(header.getAttribute("spt_subheader_id"));\n            if (subheader) {\n                var items = subheader.getElements(".spt_tab_subheader_item");\n                for (var i = 0; i < items.length; i++) {\n                    var subheader_element_name = items[i].getAttribute("spt_element_name");\n                    var subheader_content = spt.tab.get_content(subheader_element_name);\n                    spt.behavior.destroy_element(subheader_content);\n\n                }\n                spt.behavior.destroy_element(subheader);\n            }\n        }\n\n        //header.destroy();\n        //content.destroy();\n        spt.behavior.destroy_element(header);\n        spt.behavior.destroy_element(content);\n\n        //spt.tab.resize_headers();\n\n\n        var last_element_name = spt.tab.get_last_selected_element_name();\n        last_element_name = null;\n        // make the opener active\n        if (opener) {\n             spt.tab.select(opener);\n        }\n        else if (last_element_name) {\n            spt.tab.select(last_element_name);\n        }\n        else {\n            // select last one from the remaining\n            headers = spt.tab.get_headers();\n            var last = headers[headers.length - 1].getAttribute("spt_element_name");\n            spt.tab.select(last);\n        }\n\n        if (top.hasClass("spt_tab_save_state") ) {\n            spt.tab.save_state();\n        }\n    }\n   \n    var changed_el = content.getElement(".spt_has_changes");\n    var changed_row = content.getElement(".spt_row_changed");\n    \n    if (changed_el) {\n        spt.confirm("There are unsaved changes in the current tab. Continue without saving?", ok, null, {ok_args : [changed_el, "spt_has_changed"]});\n    }\n    else if (changed_row) {\n        spt.confirm("There are unsaved changes in the current tab. Continue without saving?", ok, null, {ok_args: [changed_row, "spt_row_changed"]});\n    }\n    else {\n       ok(false);\n    } \n}\n\nspt.tab.view_definition = function(bvr) {\n    var activator = spt.smenu.get_activator(bvr);\n    var header = activator;\n    var kwargs_str = header.getAttribute("spt_kwargs");\n    var kwargs;\n    if (kwargs_str != \'\') {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n        kwargs = JSON.parse(kwargs_str);\n    }\n    else {\n        kwargs = {};\n    }\n    \n    var class_name = header.getAttribute("spt_class_name_decoded");\n    \n\n    /* TEST: show widget editor\n    var class_name2 = \'tactic.ui.tools.WidgetEditorWdg\';\n    var kwargs2 = {\n        \'editor_id\': bvr.editor_id,\n        \'display_handler\': class_name,\n        \'display_options\': kwargs,\n    }\n    spt.panel.load_popup("Widget Editor", class_name2, kwargs2);\n    */\n\n\n    var br = \'\\n\';\n    var xml = \'\';\n    var placeholder = "element";\n    xml += \'<\' + placeholder + \'>\' + br;\n    xml += \'  <display class="\'+class_name+\'">\'  + br;\n    for (var name in kwargs) {\n      if (name == \'class_name\') {\n        continue;\n      }\n      xml += \'    <\'+name+\'>\'+kwargs[name]+\'</\'+name+\'>\' + br;\n    }\n    xml += \'  </display>\' + br;\n    xml += \'</\' + placeholder + \'>\';\n\n    var html = spt.convert_to_html_display(xml);\n    spt.alert(html, {type:\'html\'});\n}\n\n        '
def get_onload_js(self):
    return '\n\nif (spt.tab) {\n    return;\n}\n\nspt.Environment.get().add_library("spt_tab");\n\n\nspt.tab = {};\n\nspt.tab.top = null;\n\nspt.tab.set_main_body_tab = function() {\n    spt.tab.top = document.id(document.body).getElement(".spt_tab_top");\n    return spt.tab.top;\n}\n\n// this is to be deprecated\nspt.tab.set_main_body_top = function() {\n    spt.tab.top = document.id(\'main_body\').getElement(".spt_tab_top");\n}\n\n\nspt.tab.set_tab_top = function( tab_top ) {\n    // if this is not really a tab top, then find a child\n    if (! tab_top.hasClass("spt_tab_top") ) {\n        tab_top = tab_top.getElement(".spt_tab_top");\n    }\n    spt.tab.top = tab_top;\n    return spt.tab.top;\n}\n\n\nspt.tab.set_tab_top_from_child = function( el ) {\n    // if this is not really a tab top, then find a parent\n    if (! el.hasClass("spt_tab_top") ) {\n        el = el.getParent(".spt_tab_top");\n    }\n    \n    \n    spt.tab.top = el;\n    return spt.tab.top;\n}\n\n\nspt.tab.get_headers = function() {\n    var top = spt.tab.top;\n    var tab_id = top.getAttribute("id");\n\n    var header_top = top.getElement(".spt_tab_header_top");\n    var all_headers = header_top.getElements(".spt_tab_header");\n    //return all_headers;\n\n    var headers = [];\n    for (var i = 0; i < all_headers.length; i++ ) {\n        var header_tab_id = all_headers[i].getAttribute("spt_tab_id");\n        if (header_tab_id != tab_id) {\n            continue;\n        }\n\n        headers.push(all_headers[i]);\n    }\n\n    return headers;\n}\n\n\nspt.tab.get_header = function(name) {\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = header_top.getElements(".spt_tab_header");\n    for (var i = 0; i < headers.length; i++) {\n        if (name == headers[i].getAttribute("spt_element_name") ) {\n            return headers[i];\n        }\n    }\n    return null;\n}\n\n\n\n\nspt.tab.resize_headers = function() {\n\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n\n    var offset = 120;\n\n    var size = top.getSize();\n    top.spt_last_width = size.x;\n\n    var els = header_top.getElements(".spt_tab_header");\n    var count = els.length;\n\n    var width = parseInt((size.x-offset) / (count));\n    if (width > 120) {\n        width = 120;\n    }\n    if (width < 30) {\n        width = 30;\n    }\n\n    for (var i = 0; i < els.length; i++) {\n        els[i].setStyle("width", width + \'px\');\n        //var title_el = els[i].getElement(".spt_tab_header_label");\n        els[i].setStyle("width", width + \'px\');\n    }\n}\n\n\n\n\n\nspt.tab.get_content = function(name) {\n    var top = spt.tab.top;\n    var tab_id = top.getAttribute("spt_tab_id");\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var all_contents = content_top.getElements(".spt_tab_content");\n\n    // FIXME: this breaks when opening new tabs for some reason\n    //return all_contents;\n\n    for (var i = 0; i < all_contents.length; i++ ) {\n        var content_tab_id = all_contents[i].getAttribute("spt_tab_id");\n        var content_name = all_contents[i].getAttribute("spt_element_name");\n        if (content_name == name) {\n            return all_contents[i];\n        }\n    }\n\n\n    return null;\n}\n\n\n\n\n\nspt.tab.get_contents = function() {\n    var top = spt.tab.top;\n    var tab_id = top.getAttribute("spt_tab_id");\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var all_contents = content_top.getElements(".spt_tab_content");\n\n    // FIXME: this breaks when opening new tabs for some reason\n    //return all_contents;\n\n    var contents = [];\n    for (var i = 0; i < all_contents.length; i++ ) {\n        var content_tab_id = all_contents[i].getAttribute("spt_tab_id");\n        if (content_tab_id == null) {\n            alert(all_contents[i].getAttribute("spt_element_name"));\n        }\n        if (content_tab_id != tab_id) {\n            continue;\n        }\n\n        contents.push(all_contents[i]);\n    }\n\n\n    return contents;\n}\n\n\n\n\nspt.tab.set_attribute = function(element_name, name, value) {\n    var header = spt.tab.get_header(element_name);\n    var kwargs_str = header.getAttribute("spt_kwargs");\n    var kwargs;\n    if (kwargs_str != \'\') {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\')\n        kwargs = JSON.parse(kwargs_str);\n    }\n    else {\n        kwargs = {};\n    }\n\n    kwargs[name] = value;\n    header.setAttribute("spt_"+name, value);\n\n    kwargs_str = JSON.stringify(kwargs);\n    kwargs_str = kwargs_str.replace(/"/g,"\\&amp;quot\\;");\n    header.setAttribute("spt_kwargs", kwargs_str);\n\n}\n\n\n\n\n\nspt.tab.add_new = function(element_name, title, class_name, kwargs,\n        values, hash) {\n\n    if (typeof(title) == \'undefined\') {\n        title = \'(Untitled)\';\n    }\n    if (typeof(element_name) == \'undefined\') {\n        //alert("No element name provided");\n        //return;\n        element_name = "__default__";\n    }\n    if (typeof(class_name) == \'undefined\') {\n        class_name = \'\';\n    }\n    if (typeof(kwargs) == \'undefined\') {\n        kwargs = {};\n    }\n    if (typeof(values) == \'undefined\') {\n        values = {};\n    }\n\n    var top = spt.tab.top;\n    if (!top) {\n        spt.tab.set_main_body_tab();\n        top = spt.tab.top;\n    }\n\n    if (!hash && hash != false && kwargs.hash) {\n        hash = kwargs.hash;\n    }\n    if (hash == "__link__") {\n        hash = "link/" + element_name;\n    }\n\n\n    var orig_element_name = element_name;\n\n    var mode = top.getAttribute("spt_tab_mode");\n    if (mode == "hidden") {\n        element_name = "__default__";\n    }\n\n    var unique = kwargs.unique;\n    if (unique == true || unique == "true") {\n        var header = spt.tab.get_header(element_name);\n        if (header) {\n            var num = Math.floor((Math.random()*10000)+1); \n            element_name = element_name + num;\n        }\n    }\n\n\n    var top_id = top.getAttribute("spt_tab_id");\n\n    // disable sub tabs for now\n    full_element_name = element_name;\n    subelement_name = ;\n    /*\n    if (element_name.indexOf("/") != -1) {\n        var full_element_name = element_name;\n        var parts = element_name.split("/");\n        element_name = parts[0];\n        var subelement_name = parts[1];\n    }\n    else {\n        var full_element_name = element_name;\n        var subelement_name = ;\n    }\n    */\n\n\n    var subelement_title;\n    var full_title;\n    if (title.indexOf("/") != -1) {\n        full_title = title;\n        var parts = title.split("/");\n        title = parts[0];\n        subelement_title = parts[1];\n    }\n    else {\n        full_title = title;\n        subelement_title = title;\n    }\n\n   \n    //var headers = header_top.getElements(".spt_tab_header");\n    var headers = spt.tab.get_headers();\n\n    if (headers.length > 20) {\n        spt.alert("You have too many tabs open. Please close before opening any others.");\n        return;\n    }\n\n    var header;\n    var found = false;\n    for (var k=0; k < headers.length; k++){\n        var existing_header = headers[k];\n        if (existing_header.getAttribute(\'spt_element_name\')==element_name){\n            header = existing_header;\n            found = true;\n            break;\n        }\n    }\n\n    // add a new tab\n    if (!found) {\n        var template_top = top.getElement(".spt_tab_template_top");\n        var header_template = template_top.getElement(".spt_tab_header");\n\n        // clone the header template\n        var header = spt.behavior.clone(header_template);\n        var header_id = Math.floor(Math.random()*10000000+1);\n        header.setAttribute("id", header_id);\n\n        if (kwargs.hidden == "true") {\n            header.setStyle("display", "none");\n        }\n\n\n        // add a subheader template for each header\n        var subheader_template = template_top.getElement(".spt_tab_subheader");\n        if (subheader_template) {\n            var subheader = spt.behavior.clone(subheader_template);\n\n            var subheader_id = Math.floor(Math.random()*10000000+1);\n            header.setAttribute("spt_subheader_id", subheader_id);\n\n            subheader.setAttribute("id", subheader_id);\n            subheader.setStyle("display", "none");\n\n            subheader.setAttribute("spt_header_id", header_id);\n\n            subheader_top = top.getElement(".spt_tab_subheader_top")\n            subheader.inject(subheader_top);\n        }\n       \n\n        var last_header = headers[headers.length -1];\n\n        // set the new label\n        var label = header.getElement(".spt_tab_header_label");\n        var display_title = title;\n\n        label.setAttribute("title", title);\n        label.innerHTML = display_title;\n\n        header.setAttribute("spt_class_name", class_name);\n        var kwargs_str = JSON.stringify(kwargs);\n        kwargs_str = kwargs_str.replace(/\\"/,"\\&amp;quot\\;");\n        header.setAttribute("spt_kwargs", kwargs_str);\n        header.setAttribute("spt_element_name", element_name);\n        header.setAttribute("spt_title", title);\n        header.setAttribute("spt_tab_id", top_id);\n        header.removeClass("spt_content_loaded");\n        header.inject(last_header, "after");\n\n        spt.tab.resize_headers();\n\n\n        var selected_header = spt.tab.get_selected_header();\n        if (selected_header) {\n            var opener = selected_header.getAttribute("spt_element_name");\n            header.setAttribute("spt_tab_opener", opener);\n        }\n\n        // copy the content from template\n        var content_top = top.getElement(".spt_tab_content_top");\n        var content_template = template_top.getElement(".spt_tab_content");\n        var content_box = spt.behavior.clone(content_template);\n\n        content_box.setAttribute("spt_element_name", element_name);\n        content_box.setAttribute("spt_title", title);\n        content_box.setAttribute("spt_tab_id", top_id);\n\n        var content_boxes = spt.tab.get_contents();\n        var last_content = content_boxes[content_boxes.length -1];\n        content_box.inject(last_content, "after");\n\n        if (kwargs.count) {\n            var count_div = header.getElement(".spt_tab_header_count");\n\n            var expression = kwargs.count;\n            var search_key = kwargs.search_key;\n\n            var server = TacticServerStub.get();\n            var count = server.eval(expression, {search_keys: search_key});\n\n            count_div.innerText = count;\n\n            var update_data = {\n                expression: expression,\n                expr_key: search_key\n            };\n\n            spt.update.add(count_div, update_data);\n        }\n\n    }\n\n\n    // if a subtab is needed, create that\n    if (subelement_name) {\n        // find out if the subheader exists\n        var subheader_id = header.getAttribute("spt_subheader_id");\n        var subheader_top = document.id(subheader_id);\n        var subheaders = subheader_top.getElements(".spt_tab_subheader_item");\n\n        var subheader_exists = false;\n        var subheader = null;\n        for (var i = 0; i < subheaders.length; i++) {\n            var box_name = subheaders[i].getAttribute("spt_element_name");\n            if (full_element_name == box_name) {\n                subheader_exists = true;\n                subheader = subheaders[i];\n                break;\n            }\n        }\n\n        if (subheader_exists == false) {\n\n            // create a new one\n            var subheader = document.id(document.createElement("div"));\n            subheader.innerHTML = "<div style=\'padding: 5px 5px\'><div class=\'spt_tab_header_label\'>"+subelement_name+"</div></div>";\n            subheader_top.appendChild(subheader);\n            subheader.addClass("spt_tab_subheader_item");\n\n\n            // set the new label\n            var label = subheader.getElement(".spt_tab_header_label");\n            var display_title = subelement_title;\n            if (display_title.length > 20) {\n                display_title = subelement_title.substr(0,18) + "...";\n            }\n            title = subelement_name;\n\n            label.setAttribute("title", subelement_title);\n            label.innerHTML = display_title;\n\n            subheader.setAttribute("spt_class_name", class_name);\n            var kwargs_str = JSON.stringify(kwargs);\n            kwargs_str = kwargs_str.replace(/\\"/,"\\&amp;quot\\;");\n            subheader.setAttribute("spt_kwargs", kwargs_str);\n            subheader.setAttribute("spt_element_name", full_element_name);\n            subheader.setAttribute("spt_title", full_title);\n            subheader.setAttribute("spt_tab_id", top_id);\n            subheader.removeClass("spt_content_loaded");\n\n\n            // copy the content from template\n            var template_top = top.getElement(".spt_tab_template_top");\n            var content_top = top.getElement(".spt_tab_content_top");\n            var content_template = template_top.getElement(".spt_tab_content");\n            var content_box = spt.behavior.clone(content_template);\n\n            content_box.setAttribute("spt_element_name", full_element_name);\n            content_box.setAttribute("spt_title", full_title);\n            content_box.setAttribute("spt_tab_id", top_id);\n\n            var content_boxes = spt.tab.get_contents();\n            var last_content = content_boxes[content_boxes.length -1];\n            content_box.inject(last_content, "after");\n\n\n        }\n\n    }\n\n\n    if (! class_name) {\n        spt.tab.select(element_name);\n    }\n    else if (subelement_name) {\n        var force = true;\n        spt.tab.load_class(subheader, class_name, kwargs, values, force);\n    }\n    else {\n        var force = true;\n        spt.tab.load_class(header, class_name, kwargs, values, force);\n    }\n\n    // FIXME: this should only move on the main table\n    //var top_pos = spt.tab.getY(header_top);\n    //scroll(0,top_pos-20);\n\n\n    // register the hash\n    if (hash) {\n        var state = {\n            element_name: orig_element_name,\n            title: title,\n            class_name: class_name,\n            kwargs: kwargs,\n            hash: hash,\n            mode: \'tab\',\n        }\n        spt.hash.set_hash(state, title, hash);\n    }\n\n    if (top.hasClass("spt_tab_save_state") ) {\n        spt.tab.save_state();\n    }\n\n\n    return header;\n}\n\n// TEST\nspt.tab.getY = function(oElement)\n{\n    var iReturnValue = 0;\n        while( oElement != null ) {\n        iReturnValue += oElement.offsetTop;\n        oElement = oElement.offsetParent;\n    }\n    return iReturnValue;\n}\n\n\n\nspt.tab.load_selected = function(element_name, title, class_name, kwargs, values) {\n    var top = spt.tab.top;\n\n\n    var header = spt.tab.get_selected_header();\n    // if none are selected, use the last one\n    if (header == null) {\n        var headers = spt.tab.get_headers();\n        header = headers[headers.length - 1];\n    }\n\n    var old_element_name = header.getAttribute("spt_element_name");\n\n    header.setAttribute("spt_element_name", element_name);\n    header.setAttribute("spt_title", title);\n    header.setAttribute("spt_class_name", class_name);\n\n    if (typeof(kwargs) == \'undefined\') {\n        kwargs = {};\n    }\n    var kwargs_str = JSON.stringify(kwargs)\n    header.setAttribute("spt_kwargs", kwargs_str);\n\n    var label = header.getElement(".spt_tab_header_label");\n    var display_title = title;\n    if (display_title.length > 20) {\n        display_title = title.substr(0,18) + "...";\n    }\n    label.innerHTML = display_title;\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = content_top.getElements(".spt_tab_content");\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == old_element_name) {\n            content_box.setAttribute("spt_element_name", element_name)\n            break;\n        }\n    }\n    \n \n    var force = true; \n    spt.tab.load_class(header, class_name, kwargs, values, force);\n}\n\n\n\n// add a DOM node to the named content\nspt.tab.load_node = function(element_name, node) {\n    var top = spt.tab.top;\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = spt.tab.get_contents();\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == element_name) {\n\n            if(content_box.hasChildNodes()) {\n                while(content_box.childNodes.length >= 1 ) {\n                    content_box.removeChild(content_box.firstChild);\n                }\n            }\n\n            content_box.appendChild(node);\n\n\n            break;\n        }\n    }\n\n}    \n\n// add raw HTML to the named content\nspt.tab.load_html = function(element_name, html) {\n    var top = spt.tab.top;\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = spt.tab.get_contents();\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == element_name) {\n           spt.behavior.replace_inner_html(content_box, html);\n        }\n    }\n\n}    \n \n\n\n\nspt.tab.select = function(element_name) {\n\n    var header = spt.tab.get_header(element_name);\n    var top = spt.tab.top;\n\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = spt.tab.get_headers();\n    for (var i=0; i < headers.length; i++) {\n        headers[i].setStyle("opacity", "0.4");\n        headers[i].setStyle("font-weight", "normal");\n        headers[i].removeClass("spt_is_selected");\n        headers[i].removeClass("spt_tab_selected");\n        headers[i].addClass("spt_tab_unselected");\n    }\n    if (header) {\n        header.setStyle("opacity", "1.0");\n        header.addClass("spt_is_selected");\n        header.addClass("spt_tab_selected");\n        header.removeClass("spt_tab_unselected");\n    }\n\n    var content_top = top.getElement(".spt_tab_content_top");\n    var content_boxes = spt.tab.get_contents();\n\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        content_box.setStyle("display", "none");\n    }\n\n    for (var i=0; i < content_boxes.length; i++) {\n        var content_box = content_boxes[i];\n        var box_name = content_box.getAttribute("spt_element_name")\n        if (box_name == element_name) {\n            content_box.setStyle("display", );\n            if (!content_box.hasClass("spt_content_loaded")) {\n                spt.tab.load_class(header);\n            }\n            break;\n        }\n    }\n\n\n    var kwargs_str = header ? header.getAttribute("spt_kwargs") : \'\';\n    if (!kwargs_str) {\n        kwargs = {};\n    }\n    else {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n        kwargs = JSON.parse(kwargs_str);\n    }\n\n    bvr.options = {\n      element_name: element_name,\n      alias: kwargs.help_alias\n    }\n    spt.named_events.fire_event("tab|select", bvr);\n    \n    // usually a tab contains a table and layout. it\'s better to set to that.\n    var tab_content = top.getElement(\'.spt_tab_content[spt_element_name=\' + element_name + \']\');\n    if (tab_content) {\n        var table = tab_content.getElement(\'.spt_table_table\');\n        if (table) {\n            var layout = table.getParent(".spt_layout");\n            spt.table.set_layout(layout);\n        }\n\n        var last_element_name = spt.tab.get_selected_element_name();\n        if (last_element_name) {\n            top.setAttribute("spt_last_element_name", last_element_name);\n        }\n\n        return true;\n    } else {\n\n        return false;\n    }\n\n\n}\n\n\n\nspt.tab.load_class = function(header, class_name, kwargs, values, force) {\n    var title = header.getAttribute("spt_title");\n    var tab_element_name = header.getAttribute("spt_element_name");\n\n    if (typeof(force) == \'undefined\') {\n         force = false;\n    }\n\n    if (typeof(class_name) == \'undefined\') {\n        var class_name = header.getAttribute("SPT_WIDGET_KEY");\n        if (! class_name) {\n            class_name = header.getAttribute("spt_class_name");\n        }\n    }\n\n    if (typeof(kwargs) == \'undefined\') {\n        kwargs = {};\n        var kwargs_str = header.getAttribute("spt_kwargs");\n        if (kwargs_str) {\n            kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n            kwargs = JSON.parse(kwargs_str);\n        } \n    }\n\n\n\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n    var top_id = top.getAttribute("id");\n\n    //spt.api.app_busy_show("Loading " + title, \'\');\n\n    setTimeout( function() {\n\n        var header_top = header.getParent(".spt_tab_header_top");\n        var headers = spt.tab.get_headers();\n        for (var i=0; i < headers.length; i++) {\n            headers[i].setStyle("opacity", "0.4");\n            headers[i].setStyle("font-weight", "normal");\n            headers[i].removeClass("spt_is_selected");\n            headers[i].removeClass("spt_tab_selected");\n            headers[i].addClass("spt_tab_unselected");\n        }\n\n\n        // select the header\n        if (header.hasClass("spt_tab_subheader_item")) {\n            var subheader_top = header.getParent(".spt_tab_subheader");\n            header_id = subheader_top.getAttribute("spt_header_id");\n            select_header = document.id(header_id);\n        }\n        else {\n            select_header = header;\n        }\n\n        // select the header\n        select_header.setStyle("opacity", "1.0");\n        select_header.addClass("spt_is_selected");\n        select_header.addClass("spt_tab_selected");\n        select_header.removeClass("spt_tab_unselected");\n\n\n\n\n        var content_top = top.getElement(".spt_tab_content_top");\n        var content_boxes = spt.tab.get_contents();\n\n        // make all of the content boxes disappear\n        for (var i=0; i < content_boxes.length; i++) {\n            var content_box = content_boxes[i];\n            content_box.setStyle("display", "none");\n        }\n\n        for (var i=0; i < content_boxes.length; i++) {\n\n            var content_box = content_boxes[i];\n            var box_name = content_box.getAttribute("spt_element_name")\n            if (box_name == tab_element_name) {\n                content_box.setStyle("display", );\n\n                // if no class name is defined, then break out\n                if (typeof(class_name) == \'undefined\' || class_name == \'\') {\n                    break;\n                }\n\n                if (force || ! content_box.hasClass("spt_content_loaded")) {\n\n                    var resize_offset = content_box.getAttribute("spt_window_resize_offset");\n\n                    spt.panel.load(content_box, class_name, kwargs, values);\n\n                    // update info on header\n                    header.setAttribute("spt_class_name", class_name);\n                    var kwargs_str = JSON.stringify(kwargs);\n                    kwargs_str = kwargs_str.replace(/\\"/,"\\&amp;quot\\;");\n                    header.setAttribute("spt_kwargs", kwargs_str);\n                    header.setAttribute("spt_element_name", tab_element_name);\n                    header.setAttribute("spt_title", title);\n\n                    content_box.addClass("spt_content_loaded");\n                    // have to set this again because load removes it\n                    content_box.setAttribute("spt_element_name", tab_element_name);\n                    content_box.setAttribute("spt_tab_id", top_id);\n                    content_box.setAttribute("spt_title", title);\n\n                    if (resize_offset) {\n                        content_box.setAttribute("spt_window_resize_offset", resize_offset);\n                    }\n\n                }\n                break;\n            }\n        }\n\n        var bvr = {};\n        var parts = tab_element_name.split("/");\n        var element_name = parts[parts.length-1];\n\n        var alias = kwargs.help_alias;\n        bvr.options = {\n          element_name: element_name,\n          alias: alias\n        }\n        spt.named_events.fire_event("tab|select", bvr);\n        spt.api.app_busy_hide();\n\n      }, 10 );\n\n    \n}\n\n\nspt.tab.reload_selected = function() {\n    var header = spt.tab.get_selected_header();\n    var class_name = header.getAttribute("spt_class_name");\n    var kwargs = header.getAttribute("spt_kwargs");\n\n    var kwargs_str = header.getAttribute("spt_kwargs");\n    var kwargs;\n    if (kwargs_str != \'\') {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n        kwargs = JSON.parse(kwargs_str);\n    }\n    else {\n        kwargs = {};\n    }\n\n    var values = null;\n    var force = true;\n    spt.tab.load_class(header, class_name, kwargs, values, force);\n}\n\n\n\nspt.tab.get_selected_header = function() {\n    var top = spt.tab.top;\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = header_top.getElements(".spt_tab_header");\n    for (var i = 0; i < headers.length; i++) {\n        var header = headers[i];\n        if ( header.hasClass("spt_is_selected") ) {\n            return header;\n        }\n        \n    }\n    return null;\n}\n\n\nspt.tab.get_selected_element_name = function() {\n    var header = spt.tab.get_selected_header();\n    if (header) {\n        var element_name = header.getAttribute("spt_element_name");\n        return element_name;\n    }\n    return ;\n}\n\n\nspt.tab.get_last_selected_element_name = function() {\n    var top = spt.tab.top;\n    return top.getAttribute("spt_last_element_name");\n}\n\n\nspt.tab.save_state = function() {\n    var top = spt.tab.top;\n    var save_state = top.getAttribute("spt_tab_save_state");\n\n    var header_top = top.getElement(".spt_tab_header_top");\n    var headers = header_top.getElements(".spt_tab_header");\n\n    var class_names = [];\n    var attrs_list = [];\n    var kwargs_list = [];\n    for (var i = 0; i < headers.length; i++) {\n        var header = headers[i];\n\n        var element_name = header.getAttribute("spt_element_name")\n        var title = header.getAttribute("spt_title")\n        var attrs = {\n            name: element_name,\n            title: title\n        };\n        \n\n        var class_name = header.getAttribute("spt_class_name");\n        class_names.push(class_name);\n        var kwargs_str = header.getAttribute("spt_kwargs");\n\n        var kwargs;\n        if (kwargs_str) {\n            kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n            kwargs = JSON.parse(kwargs_str);\n        }\n        else {\n            kwargs = {};\n        }\n        kwargs_list.push(kwargs);\n\n        if (kwargs.count)\n            attrs.count = kwargs.count;\n        attrs_list.push(attrs)\n    }\n\n    var server = TacticServerStub.get();\n    var command = \'tactic.ui.container.TabSaveStateCmd\';\n    var kwargs = {\n        class_names: class_names,\n        attrs_list: attrs_list,\n        kwargs_list: kwargs_list,\n        save_state: save_state\n    };\n    server.execute_cmd(command, kwargs, {}, { \n        on_complete: function(ret_val) {console.log(ret_val)}, \n        on_error: function(err) {console.log(err)} \n    });\n\n}\n\n\n\n\nspt.tab.header_pos = null;\nspt.tab.mouse_pos = null;\nspt.tab.dragging = false;\n\nspt.tab.header_drag_setup = function( evt, bvr, mouse_411) {\n    spt.tab.top = bvr.src_el.getParent(".spt_tab_top");\n    spt.tab.header_pos = bvr.src_el.getPosition(spt.tab.top);\n    spt.tab.mouse_pos = {x: mouse_411.curr_x, y: mouse_411.curr_y};\n    var header = bvr.src_el;\n    var element_name = header.getAttribute("spt_element_name");\n    spt.tab.select(element_name);\n}\n\nspt.tab.header_drag_motion = function( evt, bvr, mouse_411) {\n    //var header = bvr.drag_el;\n    var header = bvr.src_el;\n    var dx = mouse_411.curr_x - spt.tab.mouse_pos.x;\n    var dy = mouse_411.curr_y - spt.tab.mouse_pos.y;\n    if (Math.abs(dx) < 20) {\n        spt.tab.dragging = false;\n        return;\n    }\n    spt.tab.dragging = true;\n    header.setStyle("position", "absolute");\n    header.setStyle("z-index", "100");\n    header.setStyle("opacity", "1.0");\n\n    header.setStyle("left", spt.tab.header_pos.x + dx - 10 );\n    //header.setStyle("top", spt.tab.header_pos.y + dy );\n}\n\nspt.tab.header_drag_action = function( evt, bvr, mouse_411) {\n    var header = bvr.src_el;\n    var drag_pos = header.getPosition();\n    if (spt.tab.dragging == false)\n        return;\n\n    \n    var headers = spt.tab.get_headers();\n    for ( var i = headers.length-1; i >= 0; i-- ) {\n        if (headers[i] == header) {\n            continue;\n        }\n\n        if (headers[i].getStyle("display") == "none") {\n            continue;\n        }\n\n        var pos = headers[i].getPosition();\n\n        var size = headers[i].getSize();\n        // the y ensures 2nd row tabs don\'t jump to first row on click\n        if (drag_pos.x > pos.x + size.x/2 && drag_pos.y >= pos.y) {\n            header.inject(headers[i], "after");\n            break;\n        }\n        if (drag_pos.x > pos.x && drag_pos.y >= pos.y ) {\n            header.inject(headers[i], "before");\n            break;\n        }\n\n\n\n    }\n\n    bvr.drag_el.setStyle("position", "relative");\n    bvr.drag_el.setStyle("z-index", );\n    bvr.drag_el.setStyle("top", );\n    bvr.drag_el.setStyle("left", );\n\n    bvr.drag_el.setStyle("background", bvr.gradient);\n\n    var top = spt.tab.top;\n    if (top.hasClass("spt_tab_save_state") ) {\n        spt.tab.save_state();\n    }\n\n}\n\n\nspt.tab.close = function(src_el) {\n    // src_el should be a child of spt_tab_content or spt_tab_header\n    if (!src_el) {\n        spt.error(\'src_el passed in to spt.tab.close() does not exist.\');\n        return;\n    }\n    spt.tab.top = src_el.getParent(".spt_tab_top");\n    \n    var top = spt.tab.top;\n    var headers = spt.tab.get_headers();\n    if (headers.length == 1) {\n        return;\n    }\n\n\n    var content = src_el.getParent(".spt_tab_content");\n    var element_name;\n    // check if it\'s a header child\n    if (src_el.hasClass("spt_tab_header")) {\n        var header = src_el;\n    }\n    else {\n        var header = src_el.getParent(".spt_tab_header");\n    }\n    var subheader = src_el.getParent(".spt_tab_subheader");\n    if (header) {\n        element_name = header.getAttribute("spt_element_name");\n        content = spt.tab.get_content(element_name);\n    } else if (subheader) {\n        element_name = header.getAttribute("spt_element_name");\n        content = spt.tab.get_content(element_name);\n    } else if (content) {\n        element_name = content.getAttribute("spt_element_name");\n        header = spt.tab.get_selected_header(element_name);\n    } \n\n    if (!header || !content) {\n        spt.error(\'Tab close cannot find the header or content. Abort\');\n        return;\n    }\n\n    \n    /* If there are changed elements in the current tab, changedParameters\n     * is a list with index 0 containing changed element, and index 1 containing\n     * change type class. Otherwise, changedParameters is false. \n     */\n    function ok(changedParameters) {\n        //Remove unsaved changes flags\n        if (changedParameters) {\n            var changed_element = changedParameters[0];\n            var changed_type = changedParameters[1];\n            changed_element.removeClass(changed_type);\n        }\n        var opener = header.getAttribute("spt_tab_opener");\n        var element_name = header.getAttribute("spt_element_name");\n\n        if (header) {\n            var subheader = document.id(header.getAttribute("spt_subheader_id"));\n            if (subheader) {\n                var items = subheader.getElements(".spt_tab_subheader_item");\n                for (var i = 0; i < items.length; i++) {\n                    var subheader_element_name = items[i].getAttribute("spt_element_name");\n                    var subheader_content = spt.tab.get_content(subheader_element_name);\n                    spt.behavior.destroy_element(subheader_content);\n\n                }\n                spt.behavior.destroy_element(subheader);\n            }\n        }\n\n        //header.destroy();\n        //content.destroy();\n        spt.behavior.destroy_element(header);\n        spt.behavior.destroy_element(content);\n\n        //spt.tab.resize_headers();\n\n\n        var last_element_name = spt.tab.get_last_selected_element_name();\n        last_element_name = null;\n        // make the opener active\n        if (opener) {\n             spt.tab.select(opener);\n        }\n        else if (last_element_name) {\n            spt.tab.select(last_element_name);\n        }\n        else {\n            // select last one from the remaining\n            headers = spt.tab.get_headers();\n            var last = headers[headers.length - 1].getAttribute("spt_element_name");\n            spt.tab.select(last);\n        }\n\n        if (top.hasClass("spt_tab_save_state") ) {\n            spt.tab.save_state();\n        }\n    }\n   \n    var changed_el = content.getElement(".spt_has_changes");\n    var changed_row = content.getElement(".spt_row_changed");\n    \n    if (changed_el) {\n        spt.confirm("There are unsaved changes in the current tab. Continue without saving?", ok, null, {ok_args : [changed_el, "spt_has_changed"]});\n    }\n    else if (changed_row) {\n        spt.confirm("There are unsaved changes in the current tab. Continue without saving?", ok, null, {ok_args: [changed_row, "spt_row_changed"]});\n    }\n    else {\n       ok(false);\n    } \n}\n\nspt.tab.view_definition = function(bvr) {\n    var activator = spt.smenu.get_activator(bvr);\n    var header = activator;\n    var kwargs_str = header.getAttribute("spt_kwargs");\n    var kwargs;\n    if (kwargs_str != \'\') {\n        kwargs_str = kwargs_str.replace(/\\&amp;quot\\;/g, \'"\');\n        kwargs = JSON.parse(kwargs_str);\n    }\n    else {\n        kwargs = {};\n    }\n    \n    var class_name = header.getAttribute("spt_class_name_decoded");\n    \n\n    /* TEST: show widget editor\n    var class_name2 = \'tactic.ui.tools.WidgetEditorWdg\';\n    var kwargs2 = {\n        \'editor_id\': bvr.editor_id,\n        \'display_handler\': class_name,\n        \'display_options\': kwargs,\n    }\n    spt.panel.load_popup("Widget Editor", class_name2, kwargs2);\n    */\n\n\n    var br = \'\\n\';\n    var xml = \'\';\n    var placeholder = "element";\n    xml += \'<\' + placeholder + \'>\' + br;\n    xml += \'  <display class="\'+class_name+\'">\'  + br;\n    for (var name in kwargs) {\n      if (name == \'class_name\') {\n        continue;\n      }\n      xml += \'    <\'+name+\'>\'+kwargs[name]+\'</\'+name+\'>\' + br;\n    }\n    xml += \'  </display>\' + br;\n    xml += \'</\' + placeholder + \'>\';\n\n    var html = spt.convert_to_html_display(xml);\n    spt.alert(html, {type:\'html\'});\n}\n\n        '