Skip to content

Commit

Permalink
Merge pull request ipython#4250 from pablooliveira/wrap-svg-in-iframes
Browse files Browse the repository at this point in the history
outputarea.js: Wrap inline SVGs inside an iframe
  • Loading branch information
ivanov committed Nov 11, 2013
2 parents 999d292 + deb6dbb commit 9c092f4
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 8 deletions.
60 changes: 52 additions & 8 deletions IPython/html/static/notebook/js/outputarea.js
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,51 @@ var IPython = (function (IPython) {
}
return oa;
};



OutputArea.prototype.create_output_subarea = function(md, classes) {
var subarea = $('<div/>').addClass('output_subarea').addClass(classes);
if (md['isolated']) {
// Create an iframe to isolate the subarea from the rest of the
// document
var iframe = $('<iframe/>').addClass('box-flex1');
iframe.css({'height':1, 'width':'100%', 'display':'block'});
iframe.attr('frameborder', 0);
iframe.attr('scrolling', 'auto');

// Once the iframe is loaded, the subarea is dynamically inserted
iframe.on('load', function() {
// Workaround needed by Firefox, to properly render svg inside
// iframes, see http://stackoverflow.com/questions/10177190/
// svg-dynamically-added-to-iframe-does-not-render-correctly
this.contentDocument.open();

// Insert the subarea into the iframe
// We must directly write the html. When using Jquery's append
// method, javascript is evaluated in the parent document and
// not in the iframe document.
this.contentDocument.write(subarea.html());

this.contentDocument.close();

var body = this.contentDocument.body;
// Adjust the iframe height automatically
iframe.height(body.scrollHeight + 'px');
});

// Elements should be appended to the inner subarea and not to the
// iframe
iframe.append = function(that) {
subarea.append(that);
};

return iframe;
} else {
return subarea;
}
}


OutputArea.prototype._append_javascript_error = function (err, container) {
// display a message when a javascript error occurs in display output
var msg = "Javascript error adding output!"
Expand Down Expand Up @@ -460,15 +504,15 @@ var IPython = (function (IPython) {


OutputArea.prototype.append_html = function (html, md, element) {
var toinsert = $("<div/>").addClass("output_subarea output_html rendered_html");
var toinsert = this.create_output_subarea(md, "output_html rendered_html");
toinsert.append(html);
element.append(toinsert);
};


OutputArea.prototype.append_javascript = function (js, md, container) {
// We just eval the JS code, element appears in the local scope.
var element = $("<div/>").addClass("output_subarea");
var element = this.create_output_subarea(md, "");
container.append(element);
// Div for js shouldn't be drawn, as it will add empty height to the area.
container.hide();
Expand All @@ -483,7 +527,7 @@ var IPython = (function (IPython) {


OutputArea.prototype.append_text = function (data, md, element, extra_class) {
var toinsert = $("<div/>").addClass("output_subarea output_text");
var toinsert = this.create_output_subarea(md, "output_text");
// escape ANSI & HTML specials in plaintext:
data = utils.fixConsole(data);
data = utils.fixCarriageReturn(data);
Expand All @@ -497,7 +541,7 @@ var IPython = (function (IPython) {


OutputArea.prototype.append_svg = function (svg, md, element) {
var toinsert = $("<div/>").addClass("output_subarea output_svg");
var toinsert = this.create_output_subarea(md, "output_svg");
toinsert.append(svg);
element.append(toinsert);
};
Expand Down Expand Up @@ -531,7 +575,7 @@ var IPython = (function (IPython) {


OutputArea.prototype.append_png = function (png, md, element) {
var toinsert = $("<div/>").addClass("output_subarea output_png");
var toinsert = this.create_output_subarea(md, "output_png");
var img = $("<img/>").attr('src','data:image/png;base64,'+png);
if (md['height']) {
img.attr('height', md['height']);
Expand All @@ -546,7 +590,7 @@ var IPython = (function (IPython) {


OutputArea.prototype.append_jpeg = function (jpeg, md, element) {
var toinsert = $("<div/>").addClass("output_subarea output_jpeg");
var toinsert = this.create_output_subarea(md, "output_jpeg");
var img = $("<img/>").attr('src','data:image/jpeg;base64,'+jpeg);
if (md['height']) {
img.attr('height', md['height']);
Expand All @@ -563,7 +607,7 @@ var IPython = (function (IPython) {
OutputArea.prototype.append_latex = function (latex, md, element) {
// This method cannot do the typesetting because the latex first has to
// be on the page.
var toinsert = $("<div/>").addClass("output_subarea output_latex");
var toinsert = this.create_output_subarea(md, "output_latex");
toinsert.append(latex);
element.append(toinsert);
};
Expand Down
42 changes: 42 additions & 0 deletions IPython/html/tests/casperjs/test_cases/isolated_svg.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// Test svg isolation
// An object whose metadata contains an "isolated" tag must be isolated
// from the rest of the document. In the case of inline SVGs, this means
// that multiple SVGs have different scopes. This test checks that there
// are no CSS leaks between two isolated SVGs.
//

casper.notebook_test(function () {
this.evaluate(function () {
var cell = IPython.notebook.get_cell(0);
cell.set_text( "from IPython.core.display import SVG, display_svg\n"
+ "s1 = '''<svg width='1cm' height='1cm' viewBox='0 0 1000 500'>"
+ "<defs><style>rect {fill:red;}; </style></defs>"
+ "<rect id='r1' x='200' y='100' width='600' height='300' /></svg>"
+ "'''\n"
+ "s2 = '''<svg width='1cm' height='1cm' viewBox='0 0 1000 500'>"
+ "<rect id='r2' x='200' y='100' width='600' height='300' /></svg>"
+ "'''\n"
+ "display_svg(SVG(s1), metadata=dict(isolated=True))\n"
+ "display_svg(SVG(s2), metadata=dict(isolated=True))\n"
);
cell.execute();
});

this.wait_for_output(0);

this.then(function () {
var colors = this.evaluate(function () {
var colors = [];
var ifr = __utils__.findAll("iframe");
var svg1 = ifr[0].contentWindow.document.getElementById('r1');
colors[0] = window.getComputedStyle(svg1)["fill"];
var svg2 = ifr[1].contentWindow.document.getElementById('r2');
colors[1] = window.getComputedStyle(svg2)["fill"];
return colors;
});

this.test.assertEquals(colors[0], '#ff0000', 'First svg should be red');
this.test.assertEquals(colors[1], '#000000', 'Second svg should be black');
});
});

0 comments on commit 9c092f4

Please sign in to comment.