| /** |
| * JavaScript functions enhancing the SVG diagrams. |
| * |
| * @author Damien Obrist |
| */ |
| |
| var diagrams = {}; |
| |
| /** |
| * Initializes the diagrams in the main window. |
| */ |
| $(document).ready(function() |
| { |
| // hide diagrams in browsers not supporting SVG |
| if(Modernizr && !Modernizr.inlinesvg) |
| return; |
| |
| // only execute this in the main window |
| if(diagrams.isPopup) |
| return; |
| |
| if($("#content-diagram").length) |
| $("#inheritance-diagram").css("padding-bottom", "20px"); |
| |
| $(".diagram-container").css("display", "block"); |
| |
| $(".diagram").each(function() { |
| // store initial dimensions |
| $(this).data("width", $("svg", $(this)).width()); |
| $(this).data("height", $("svg", $(this)).height()); |
| // store unscaled clone of SVG element |
| $(this).data("svg", $(this).get(0).childNodes[0].cloneNode(true)); |
| }); |
| |
| // make diagram visible, hide container |
| $(".diagram").css("display", "none"); |
| $(".diagram svg").css({ |
| "position": "static", |
| "visibility": "visible", |
| "z-index": "auto" |
| }); |
| |
| // enable linking to diagrams |
| if($(location).attr("hash") == "#inheritance-diagram") { |
| diagrams.toggle($("#inheritance-diagram-container"), true); |
| } else if($(location).attr("hash") == "#content-diagram") { |
| diagrams.toggle($("#content-diagram-container"), true); |
| } |
| |
| $(".diagram-link").click(function() { |
| diagrams.toggle($(this).parent()); |
| }); |
| |
| // register resize function |
| $(window).resize(diagrams.resize); |
| |
| // don't bubble event to parent div |
| // when clicking on a node of a resized |
| // diagram |
| $("svg a").click(function(e) { |
| e.stopPropagation(); |
| }); |
| |
| diagrams.initHighlighting(); |
| }); |
| |
| /** |
| * Initializes the diagrams in the popup. |
| */ |
| diagrams.initPopup = function(id) |
| { |
| // copy diagram from main window |
| if(!jQuery.browser.msie) |
| $("body").append(opener.$("#" + id).data("svg")); |
| |
| // positioning |
| $("svg").css("position", "absolute"); |
| $(window).resize(function() |
| { |
| var svg_w = $("svg").css("width").replace("px", ""); |
| var svg_h = $("svg").css("height").replace("px", ""); |
| var x = $(window).width() / 2 - svg_w / 2; |
| if(x < 0) x = 0; |
| var y = $(window).height() / 2 - svg_h / 2; |
| if(y < 0) y = 0; |
| $("svg").css("left", x + "px"); |
| $("svg").css("top", y + "px"); |
| }); |
| $(window).resize(); |
| |
| diagrams.initHighlighting(); |
| $("svg a").click(function(e) { |
| opener.diagrams.redirectFromPopup(this.href.baseVal); |
| window.close(); |
| }); |
| $(document).keyup(function(e) { |
| if (e.keyCode == 27) window.close(); |
| }); |
| } |
| |
| /** |
| * Initializes highlighting for nodes and edges. |
| */ |
| diagrams.initHighlighting = function() |
| { |
| // helper function since $.hover doesn't work in IE |
| |
| function hover(elements, fn) |
| { |
| elements.mouseover(fn); |
| elements.mouseout(fn); |
| } |
| |
| // inheritance edges |
| |
| hover($("svg .edge.inheritance"), function(evt){ |
| var toggleClass = evt.type == "mouseout" ? diagrams.removeClass : diagrams.addClass; |
| var parts = $(this).attr("id").split("_"); |
| toggleClass($("#" + parts[0] + "_" + parts[1])); |
| toggleClass($("#" + parts[0] + "_" + parts[2])); |
| toggleClass($(this)); |
| }); |
| |
| // nodes |
| |
| hover($("svg .node"), function(evt){ |
| var toggleClass = evt.type == "mouseout" ? diagrams.removeClass : diagrams.addClass; |
| toggleClass($(this)); |
| var parts = $(this).attr("id").split("_"); |
| var index = parts[1]; |
| $("svg#" + parts[0] + " .edge.inheritance").each(function(){ |
| var parts2 = $(this).attr("id").split("_"); |
| if(parts2[1] == index) |
| { |
| toggleClass($("#" + parts2[0] + "_" + parts2[2])); |
| toggleClass($(this)); |
| } else if(parts2[2] == index) |
| { |
| toggleClass($("#" + parts2[0] + "_" + parts2[1])); |
| toggleClass($(this)); |
| } |
| }); |
| }); |
| |
| // incoming implicits |
| |
| hover($("svg .node.implicit-incoming"), function(evt){ |
| var toggleClass = evt.type == "mouseout" ? diagrams.removeClass : diagrams.addClass; |
| toggleClass($(this)); |
| toggleClass($("svg .edge.implicit-incoming")); |
| toggleClass($("svg .node.this")); |
| }); |
| |
| hover($("svg .edge.implicit-incoming"), function(evt){ |
| var toggleClass = evt.type == "mouseout" ? diagrams.removeClass : diagrams.addClass; |
| toggleClass($(this)); |
| toggleClass($("svg .node.this")); |
| $("svg .node.implicit-incoming").each(function(){ |
| toggleClass($(this)); |
| }); |
| }); |
| |
| // implicit outgoing nodes |
| |
| hover($("svg .node.implicit-outgoing"), function(evt){ |
| var toggleClass = evt.type == "mouseout" ? diagrams.removeClass : diagrams.addClass; |
| toggleClass($(this)); |
| toggleClass($("svg .edge.implicit-outgoing")); |
| toggleClass($("svg .node.this")); |
| }); |
| |
| hover($("svg .edge.implicit-outgoing"), function(evt){ |
| var toggleClass = evt.type == "mouseout" ? diagrams.removeClass : diagrams.addClass; |
| toggleClass($(this)); |
| toggleClass($("svg .node.this")); |
| $("svg .node.implicit-outgoing").each(function(){ |
| toggleClass($(this)); |
| }); |
| }); |
| }; |
| |
| /** |
| * Resizes the diagrams according to the available width. |
| */ |
| diagrams.resize = function() |
| { |
| // available width |
| var availableWidth = $("body").width() - 20; |
| |
| $(".diagram-container").each(function() { |
| // unregister click event on whole div |
| $(".diagram", this).unbind("click"); |
| var diagramWidth = $(".diagram", this).data("width"); |
| var diagramHeight = $(".diagram", this).data("height"); |
| |
| if(diagramWidth > availableWidth) |
| { |
| // resize diagram |
| var height = diagramHeight / diagramWidth * availableWidth; |
| $(".diagram svg", this).width(availableWidth); |
| $(".diagram svg", this).height(height); |
| |
| // register click event on whole div |
| $(".diagram", this).click(function() { |
| diagrams.popup($(this)); |
| }); |
| $(".diagram", this).addClass("magnifying"); |
| } |
| else |
| { |
| // restore full size of diagram |
| $(".diagram svg", this).width(diagramWidth); |
| $(".diagram svg", this).height(diagramHeight); |
| // don't show custom cursor any more |
| $(".diagram", this).removeClass("magnifying"); |
| } |
| }); |
| }; |
| |
| /** |
| * Shows or hides a diagram depending on its current state. |
| */ |
| diagrams.toggle = function(container, dontAnimate) |
| { |
| // change class of link |
| $(".diagram-link", container).toggleClass("open"); |
| // get element to show / hide |
| var div = $(".diagram", container); |
| if (div.is(':visible')) |
| { |
| $(".diagram-help", container).hide(); |
| div.unbind("click"); |
| div.removeClass("magnifying"); |
| div.slideUp(100); |
| } |
| else |
| { |
| diagrams.resize(); |
| if(dontAnimate) |
| div.show(); |
| else |
| div.slideDown(100); |
| $(".diagram-help", container).show(); |
| } |
| }; |
| |
| /** |
| * Opens a popup containing a copy of a diagram. |
| */ |
| diagrams.windows = {}; |
| diagrams.popup = function(diagram) |
| { |
| var id = diagram.attr("id"); |
| if(!diagrams.windows[id] || diagrams.windows[id].closed) { |
| var title = $(".symbol .name", $("#signature")).text(); |
| // cloning from parent window to popup somehow doesn't work in IE |
| // therefore include the SVG as a string into the HTML |
| var svgIE = jQuery.browser.msie ? $("<div />").append(diagram.data("svg")).html() : ""; |
| var html = '' + |
| '<?xml version="1.0" encoding="UTF-8"?>\n' + |
| '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">\n' + |
| '<html>\n' + |
| ' <head>\n' + |
| ' <title>' + title + '</title>\n' + |
| ' <link href="' + $("#diagrams-css").attr("href") + '" media="screen" type="text/css" rel="stylesheet" />\n' + |
| ' <script type="text/javascript" src="' + $("#jquery-js").attr("src") + '"></script>\n' + |
| ' <script type="text/javascript" src="' + $("#diagrams-js").attr("src") + '"></script>\n' + |
| ' <script type="text/javascript">\n' + |
| ' diagrams.isPopup = true;\n' + |
| ' </script>\n' + |
| ' </head>\n' + |
| ' <body onload="diagrams.initPopup(\'' + id + '\');">\n' + |
| ' <a href="#" onclick="window.close();" id="close-link">Close this window</a>\n' + |
| ' ' + svgIE + '\n' + |
| ' </body>\n' + |
| '</html>'; |
| |
| var padding = 30; |
| var screenHeight = screen.availHeight; |
| var screenWidth = screen.availWidth; |
| var w = Math.min(screenWidth, diagram.data("width") + 2 * padding); |
| var h = Math.min(screenHeight, diagram.data("height") + 2 * padding); |
| var left = (screenWidth - w) / 2; |
| var top = (screenHeight - h) / 2; |
| var parameters = "height=" + h + ", width=" + w + ", left=" + left + ", top=" + top + ", scrollbars=yes, location=no, resizable=yes"; |
| var win = window.open("about:blank", "_blank", parameters); |
| win.document.open(); |
| win.document.write(html); |
| win.document.close(); |
| diagrams.windows[id] = win; |
| } |
| win.focus(); |
| }; |
| |
| /** |
| * This method is called from within the popup when a node is clicked. |
| */ |
| diagrams.redirectFromPopup = function(url) |
| { |
| window.location = url; |
| }; |
| |
| /** |
| * Helper method that adds a class to a SVG element. |
| */ |
| diagrams.addClass = function(svgElem, newClass) { |
| newClass = newClass || "over"; |
| var classes = svgElem.attr("class"); |
| if ($.inArray(newClass, classes.split(/\s+/)) == -1) { |
| classes += (classes ? ' ' : '') + newClass; |
| svgElem.attr("class", classes); |
| } |
| }; |
| |
| /** |
| * Helper method that removes a class from a SVG element. |
| */ |
| diagrams.removeClass = function(svgElem, oldClass) { |
| oldClass = oldClass || "over"; |
| var classes = svgElem.attr("class"); |
| classes = $.grep(classes.split(/\s+/), function(n, i) { return n != oldClass; }).join(' '); |
| svgElem.attr("class", classes); |
| }; |
| |