Skip to content

Commit

Permalink
prefix all url() references with current location (#568)
Browse files Browse the repository at this point in the history
the prefix is removed on export and added on import
  • Loading branch information
Fuzzyma committed Apr 23, 2017
1 parent 54362a8 commit 86f2910
Show file tree
Hide file tree
Showing 15 changed files with 97 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ The document follows the conventions described in [“Keep a CHANGELOG”](http:
- new constructor signature for `SVG.Image` and `load()`: `container.image(src, callback) / image.load(src, callback)`
- changed `style()` to `css()`. Now accepts array as input and returns object when no argument given (#517)
- ids are not generated upon creation anymore. Instead they are generated when requested (#559)
- prefix all `url()` references with current location so that nothing breaks when using `<base>`

### Fixed
- fixed a bug in clipping and masking where empty nodes persists after removal -> __TODO!__
Expand Down
49 changes: 43 additions & 6 deletions dist/svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* @copyright Wout Fierens <wout@mick-wout.com>
* @license MIT
*
* BUILT: Sun Apr 23 2017 12:52:05 GMT+0200 (Mitteleuropäische Sommerzeit)
* BUILT: Sun Apr 23 2017 15:09:13 GMT+0200 (Mitteleuropäische Sommerzeit)
*/;
(function(root, factory) {
/* istanbul ignore next */
Expand Down Expand Up @@ -212,6 +212,9 @@ SVG.regex = {
// Test for image url
, isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i

// Test for url reference
, isUrl: /url\(([-\w:/]+(?:\.\w+)?)?#([-\w]+)\)/

// split at whitespace and comma
, delimiter: /[\s,]+/

Expand Down Expand Up @@ -1232,6 +1235,8 @@ SVG.Element = SVG.invent({
// dump raw svg
well.innerHTML = svg

addPrefixToReferences(well)

// transplant nodes
for (len = well.childNodes.length;len--;)
if(well.firstChild.nodeType != 1)
Expand All @@ -1241,6 +1246,7 @@ SVG.Element = SVG.invent({

// otherwise act as a getter
} else {
removePrefixFromReferences(this.node)
return this.node.outerHTML
}

Expand Down Expand Up @@ -3374,7 +3380,7 @@ SVG.extend(SVG.Element, {
var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)

// apply mask
return this.attr('mask', 'url("#' + masker.id() + '")')
return this.attr('mask', url(masker))
}
// Unmask element
, unmask: function() {
Expand Down Expand Up @@ -3427,7 +3433,7 @@ SVG.extend(SVG.Element, {
var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)

// apply mask
return this.attr('clip-path', 'url("#' + clipper.id() + '")')
return this.attr('clip-path', url(clipper))
}
// Unclip element
, unclip: function() {
Expand Down Expand Up @@ -3466,7 +3472,7 @@ SVG.Gradient = SVG.invent({
}
// Return the fill id
, fill: function() {
return 'url(#' + this.id() + ')'
return url(this)
}
// Alias string convertion to fill
, toString: function() {
Expand Down Expand Up @@ -3554,7 +3560,7 @@ SVG.Pattern = SVG.invent({
, extend: {
// Return the fill id
fill: function() {
return 'url(#' + this.id() + ')'
return url(this)
}
// Update pattern by rebuilding
, update: function(block) {
Expand Down Expand Up @@ -4526,7 +4532,7 @@ SVG.Marker = SVG.invent({
}
// Return the fill id
, toString: function() {
return 'url(#' + this.id() + ')'
return url(this)
}
}

Expand Down Expand Up @@ -4972,6 +4978,37 @@ function idFromReference(url) {
if (m) return m[1]
}

// creates an url reference out of nodes id
function url(node) {
return 'url(' + window.location + '#' + node.id() + ')'

This comment has been minimized.

Copy link
@wout

wout Apr 23, 2017

Member

Just wondering, should we always prefix the location or only when a <base> tag is set in the document? We could test for the base tag once on prepare(). If one is defined, only then we add the prefix. this way we avoid the overhead when it's not set, which is probably 95% of the time.

}

function removePrefixFromReferences(node) {
for (var i = node.childNodes.length - 1; i >= 0; i--)
if (node.childNodes[i] instanceof window.SVGElement)
removePrefixFromReferences(node.childNodes[i])

var v = node.attributes, match
for (n = v.length - 1; n >= 0; n--) {
if(match = SVG.regex.isUrl.exec(v[n].nodeValue)) {
if(match[1] == window.location) v[n].nodeValue = 'url(#' + match[2] + ')'
}
}
}

function addPrefixToReferences(node) {
for (var i = node.childNodes.length - 1; i >= 0; i--)
if (node.childNodes[i] instanceof window.SVGElement)
addPrefixToReferences(node.childNodes[i])

var v = node.attributes, match
for (n = v.length - 1; n >= 0; n--) {
if(match = SVG.regex.isUrl.exec(v[n].nodeValue)) {
if(!match[1]) v[n].nodeValue = 'url(' + window.location + '#' + match[2] + ')'
}
}
}

// Create matrix array for looping
var abcdef = 'abcdef'.split('')

Expand Down
4 changes: 2 additions & 2 deletions dist/svg.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion spec/spec/clip.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('ClipPath', function() {
})

it('sets the "clip-path" attribute on the cliped element with the clip id', function() {
expect(rect.attr('clip-path')).toBe('url("#' + circle.parent().id() + '")')
expect(rect.attr('clip-path')).toBe('url(' + window.location + '#' + circle.parent().id() + ')')
})

it('references the clip element in the masked element', function() {
Expand Down
6 changes: 3 additions & 3 deletions spec/spec/gradient.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe('Gradient', function() {

describe('fill()', function() {
it('returns the id of the gradient wrapped in url()', function() {
expect(gradient.fill()).toBe('url(#' + gradient.id() + ')')
expect(gradient.fill()).toBe('url(' + window.location + '#' + gradient.id() + ')')
})
})

Expand Down Expand Up @@ -67,11 +67,11 @@ describe('Gradient', function() {

describe('toString()', function() {
it('returns the id of the gradient wrapped in url()', function() {
expect(gradient + '').toBe('url(#' + gradient.id() + ')')
expect(gradient + '').toBe('url(' + window.location + '#' + gradient.id() + ')')
})
it('is called when instance is passed as an attribute value', function() {
rect.attr('fill', gradient)
expect(rect.attr('fill')).toBe('url(#' + gradient.id() + ')')
expect(rect.attr('fill')).toBe('url(' + window.location + '#' + gradient.id() + ')')
})
})

Expand Down
2 changes: 1 addition & 1 deletion spec/spec/mask.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('Mask', function() {
})

it('sets the "mask" attribute on the masked element with the mask id', function() {
expect(rect.attr('mask')).toBe('url("#' + circle.parent().id() + '")')
expect(rect.attr('mask')).toBe('url(' + window.location + '#' + circle.parent().id() + ')')
})

it('references the mask element in the masked element', function() {
Expand Down
8 changes: 4 additions & 4 deletions spec/spec/pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ describe('Pattern', function() {

describe('fill()', function() {
it('returns the id of the pattern wrapped in url()', function() {
expect(pattern.fill()).toBe('url(#' + pattern.id() + ')')
expect(pattern.fill()).toBe('url(' + window.location + '#' + pattern.id() + ')')
})
})

Expand All @@ -37,15 +37,15 @@ describe('Pattern', function() {

describe('toString()', function() {
it('returns the id of the pattern wrapped in url()', function() {
expect(pattern + '').toBe('url(#' + pattern.id() + ')')
expect(pattern + '').toBe('url(' + window.location + '#' + pattern.id() + ')')
})
it('is called when instance is passed as an attribute value', function() {
rect.attr('fill', pattern)
expect(rect.attr('fill')).toBe('url(#' + pattern.id() + ')')
expect(rect.attr('fill')).toBe('url(' + window.location + '#' + pattern.id() + ')')
})
it('is called when instance is passed in a fill() method', function() {
rect.fill(pattern)
expect(rect.attr('fill')).toBe('url(#' + pattern.id() + ')')
expect(rect.attr('fill')).toBe('url(' + window.location + '#' + pattern.id() + ')')
})
})

Expand Down
2 changes: 1 addition & 1 deletion src/clip.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ SVG.extend(SVG.Element, {
var clipper = element instanceof SVG.ClipPath ? element : this.parent().clip().add(element)

// apply mask
return this.attr('clip-path', 'url("#' + clipper.id() + '")')
return this.attr('clip-path', url(clipper))
}
// Unclip element
, unclip: function() {
Expand Down
3 changes: 3 additions & 0 deletions src/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,8 @@ SVG.Element = SVG.invent({
// dump raw svg
well.innerHTML = svg

addPrefixToReferences(well)

// transplant nodes
for (len = well.childNodes.length;len--;)
if(well.firstChild.nodeType != 1)
Expand All @@ -229,6 +231,7 @@ SVG.Element = SVG.invent({

// otherwise act as a getter
} else {
removePrefixFromReferences(this.node)
return this.node.outerHTML
}

Expand Down
2 changes: 1 addition & 1 deletion src/gradient.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ SVG.Gradient = SVG.invent({
}
// Return the fill id
, fill: function() {
return 'url(#' + this.id() + ')'
return url(this)
}
// Alias string convertion to fill
, toString: function() {
Expand Down
31 changes: 31 additions & 0 deletions src/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -185,5 +185,36 @@ function idFromReference(url) {
if (m) return m[1]
}

// creates an url reference out of nodes id
function url(node) {
return 'url(' + window.location + '#' + node.id() + ')'
}

function removePrefixFromReferences(node) {
for (var i = node.childNodes.length - 1; i >= 0; i--)
if (node.childNodes[i] instanceof window.SVGElement)
removePrefixFromReferences(node.childNodes[i])

var v = node.attributes, match
for (n = v.length - 1; n >= 0; n--) {
if(match = SVG.regex.isUrl.exec(v[n].nodeValue)) {
if(match[1] == window.location) v[n].nodeValue = 'url(#' + match[2] + ')'
}
}
}

function addPrefixToReferences(node) {
for (var i = node.childNodes.length - 1; i >= 0; i--)
if (node.childNodes[i] instanceof window.SVGElement)
addPrefixToReferences(node.childNodes[i])

var v = node.attributes, match
for (n = v.length - 1; n >= 0; n--) {
if(match = SVG.regex.isUrl.exec(v[n].nodeValue)) {
if(!match[1]) v[n].nodeValue = 'url(' + window.location + '#' + match[2] + ')'
}
}
}

// Create matrix array for looping
var abcdef = 'abcdef'.split('')
2 changes: 1 addition & 1 deletion src/marker.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ SVG.Marker = SVG.invent({
}
// Return the fill id
, toString: function() {
return 'url(#' + this.id() + ')'
return url(this)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/mask.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ SVG.extend(SVG.Element, {
var masker = element instanceof SVG.Mask ? element : this.parent().mask().add(element)

// apply mask
return this.attr('mask', 'url("#' + masker.id() + '")')
return this.attr('mask', url(masker))
}
// Unmask element
, unmask: function() {
Expand Down
2 changes: 1 addition & 1 deletion src/pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ SVG.Pattern = SVG.invent({
, extend: {
// Return the fill id
fill: function() {
return 'url(#' + this.id() + ')'
return url(this)
}
// Update pattern by rebuilding
, update: function(block) {
Expand Down
3 changes: 3 additions & 0 deletions src/regex.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ SVG.regex = {
// Test for image url
, isImage: /\.(jpg|jpeg|png|gif|svg)(\?[^=]+.*)?/i

// Test for url reference
, isUrl: /url\(([-\w:/]+(?:\.\w+)?)?#([-\w]+)\)/

// split at whitespace and comma
, delimiter: /[\s,]+/

Expand Down

0 comments on commit 86f2910

Please sign in to comment.