blob: 680ead7a593d21f926fb2587c990d79405c0a3d1 [file] [log] [blame]
/**
* 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);
};