Fixing how styles are added to SVG documents to please IE

This also allowed the SVG element to be created in a single place
This commit is contained in:
Jeff Avallone 2014-12-24 23:01:32 -05:00
parent 000809752e
commit d21846e872
7 changed files with 54 additions and 34 deletions

View File

@ -61,18 +61,32 @@ describe('parser/javascript.js', function() {
this.parser.parsed.render.and.returnValue(this.renderPromise.promise); this.parser.parsed.render.and.returnValue(this.renderPromise.promise);
this.svgStyles = 'example styles'; this.svgStyles = 'example styles';
this.svg = Snap(document.createElement('svg')); this.svgContainer = document.createElement('div');
spyOn(this.svg, 'group').and.returnValue('example group');
}); });
it('adds the svg styles to the svg element', function() { it('creates the SVG element', function() {
this.parser.render(this.svg, this.svgStyles); var svg;
expect(this.svg.innerHTML).toEqual('<style type="text/css">example styles</style>');
this.parser.render(this.svgContainer, this.svgStyles);
svg = this.svgContainer.querySelector('svg');
expect(svg.getAttribute('xmlns')).toEqual('http://www.w3.org/2000/svg');
expect(svg.getAttribute('version')).toEqual('1.1');
});
it('sets the styles on the SVG element', function() {
var styles;
this.parser.render(this.svgContainer, this.svgStyles);
styles = this.svgContainer.querySelector('svg defs style');
expect(styles.getAttribute('type')).toEqual('text/css');
expect(styles.firstChild.nodeValue).toEqual(this.svgStyles);
}); });
it('render the parsed expression', function() { it('render the parsed expression', function() {
this.parser.render(this.svg, this.svgStyles); this.parser.render(this.svgContainer, this.svgStyles);
expect(this.parser.parsed.render).toHaveBeenCalledWith('example group'); expect(this.parser.parsed.render).toHaveBeenCalled();
}); });
describe('when rendering is complete', function() { describe('when rendering is complete', function() {
@ -86,9 +100,7 @@ describe('parser/javascript.js', function() {
height: 24 height: 24
}); });
spyOn(this.svg, 'attr'); this.parser.render(this.svgContainer, this.svgStyles);
this.parser.render(this.svg, this.svgStyles);
this.renderPromise.resolve(this.result); this.renderPromise.resolve(this.result);
setTimeout(done, 10); setTimeout(done, 10);
@ -100,10 +112,10 @@ describe('parser/javascript.js', function() {
}); });
it('sets the dimensions of the image', function() { it('sets the dimensions of the image', function() {
expect(this.svg.attr).toHaveBeenCalledWith({ var svg = this.svgContainer.querySelector('svg');
width: 62,
height: 44 expect(svg.getAttribute('width')).toEqual('62');
}); expect(svg.getAttribute('height')).toEqual('44');
}); });
}); });

View File

@ -15,7 +15,7 @@ describe('regexper.js', function() {
'<div><a href="#" data-glyph="link-intact"></a></div>', '<div><a href="#" data-glyph="link-intact"></a></div>',
'<div><a href="#" data-glyph="data-transfer-download"></a></div>', '<div><a href="#" data-glyph="data-transfer-download"></a></div>',
'<div id="progress"><div></div></div>', '<div id="progress"><div></div></div>',
'<div id="regexp-render"><svg></svg></div>', '<div id="regexp-render"></div>',
'<div id="svg-styles">example styles</div>' '<div id="svg-styles">example styles</div>'
].join(''); ].join('');
@ -429,7 +429,7 @@ describe('regexper.js', function() {
}); });
it('renders the expression', function() { it('renders the expression', function() {
expect(this.parser.render).toHaveBeenCalledWith(this.regexper.svg, this.regexper.svgStyles); expect(this.parser.render).toHaveBeenCalledWith(this.regexper.svgContainer, this.regexper.svgStyles);
}); });
}); });

View File

@ -26,10 +26,7 @@
<ul id="warnings"></ul> <ul id="warnings"></ul>
<!-- NOTE: Do not put anything in #regexp-render other than the <svg> element --> <div id="regexp-render"></div>
<div id="regexp-render">
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"></svg>
</div>
</div> </div>
<script src="/js/main.js" async defer></script> <script src="/js/main.js" async defer></script>

View File

@ -20,7 +20,7 @@ import _ from 'lodash';
element.className = _.compact([element.className, 'loading']).join(' '); element.className = _.compact([element.className, 'loading']).join(' ');
element.innerHTML = [ element.innerHTML = [
'<svg xmlns="http://www.w3.org/2000/svg" version="1.1"></svg>', '<div class="svg"></div>',
'<div class="spinner">', '<div class="spinner">',
'<div></div>', '<div></div>',
'<div></div>', '<div></div>',
@ -28,7 +28,7 @@ import _ from 'lodash';
element.innerHTML element.innerHTML
].join(''); ].join('');
svg = element.querySelector('svg'); svg = element.querySelector('.svg');
setTimeout(() => { setTimeout(() => {
parser.parse(element.getAttribute('data-expr')) parser.parse(element.getAttribute('data-expr'))

View File

@ -32,16 +32,22 @@ export default class Parser {
return deferred.promise; return deferred.promise;
} }
render(svgElement, styles) { render(containerElement, styles) {
var svg; var svg,
style = document.createElement('style');
svgElement.innerHTML = [ containerElement.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" version="1.1"></svg>';
'<style type="text/css">',
styles,
'</style>'
].join('');
svg = Snap(svgElement); svg = Snap(containerElement.querySelector('svg'));
style.setAttribute('type', 'text/css');
if (style.styleSheet) {
style.styleSheet.cssText = styles;
} else {
style.appendChild(document.createTextNode(styles));
}
svg.select('defs').append(style);
return this.parsed.render(svg.group()) return this.parsed.render(svg.group())
.then(result => { .then(result => {

View File

@ -13,7 +13,7 @@ export default class Regexper {
this.permalink = root.querySelector('a[data-glyph="link-intact"]'); this.permalink = root.querySelector('a[data-glyph="link-intact"]');
this.download = root.querySelector('a[data-glyph="data-transfer-download"]'); this.download = root.querySelector('a[data-glyph="data-transfer-download"]');
this.percentage = root.querySelector('#progress div'); this.percentage = root.querySelector('#progress div');
this.svg = root.querySelector('#regexp-render svg'); this.svgContainer = root.querySelector('#regexp-render');
this.svgStyles = this.root.querySelector('#svg-styles').innerHTML; this.svgStyles = this.root.querySelector('#svg-styles').innerHTML;
this.gaq = (typeof window._gaq === 'undefined') ? [] : window._gaq; this.gaq = (typeof window._gaq === 'undefined') ? [] : window._gaq;
@ -108,7 +108,7 @@ export default class Regexper {
updateLinks() { updateLinks() {
try { try {
this.download.parentNode.style.display = null; this.download.parentNode.style.display = null;
this.download.href = this.buildBlobURL(this.svg.parentNode.innerHTML); this.download.href = this.buildBlobURL(this.svgContainer.innerHTML);
} }
catch(e) { catch(e) {
// Blobs or URLs created from them don't work here. // Blobs or URLs created from them don't work here.
@ -158,7 +158,7 @@ export default class Regexper {
throw message; throw message;
}) })
.invoke('render', this.svg, this.svgStyles) .invoke('render', this.svgContainer, this.svgStyles)
.then(() => { .then(() => {
this.state = 'has-results'; this.state = 'has-results';
this.updateLinks(); this.updateLinks();

View File

@ -264,12 +264,17 @@ header {
margin-left: -24px; margin-left: -24px;
} }
svg { .svg {
position: absolute; position: absolute;
top: -10000px; top: -10000px;
} }
} }
.svg {
margin: 0;
text-align: center;
}
figcaption { figcaption {
@include adjust-font-size-to($base-font-size); @include adjust-font-size-to($base-font-size);
background: $green; background: $green;