/**
 * List of SVG attributes to fix url target in them
 * @type {string[]}
 */
var fixAttributes = [
  'clipPath',
  'colorProfile',
  'src',
  'cursor',
  'fill',
  'filter',
  'marker',
  'markerStart',
  'markerMid',
  'markerEnd',
  'mask',
  'stroke'
];

/**
 * Query to find'em
 * @type {string}
 */
var fixAttributesQuery = '[' + fixAttributes.join('],[') + ']';
/**
 * @type {RegExp}
 */
var URI_FUNC_REGEX = /^url\((.*)\)$/;

/**
 * Convert array-like to array
 * @param {Object} arrayLike
 * @returns {Array.<T>}
 */
function arrayFrom(arrayLike) {
  return Array.prototype.slice.call(arrayLike, 0);
}

/**
 * Handles forbidden symbols which cannot be directly used inside attributes with url(...) content.
 * Adds leading slash for the brackets
 * @param url
 * @return encoded url
 */
function encodeUrlForEmbedding(url) {
  return url.replace(/\(|\)/, "\\$&");
}

/**
 * Replaces prefix in `url()` functions
 * @param {Element} svg
 * @param {string} currentUrlPrefix
 * @param {string} newUrlPrefix
 */
function baseUrlWorkAround(svg, currentUrlPrefix, newUrlPrefix) {
  var nodes = svg.querySelectorAll(fixAttributesQuery);

  if (!nodes) {
    return;
  }

  arrayFrom(nodes).forEach(function (node) {
    if (!node.attributes) {
      return;
    }

    arrayFrom(node.attributes).forEach(function (attribute) {
      if (fixAttributes.indexOf(attribute.localName) !== -1) {
        var match = URI_FUNC_REGEX.exec(node.getAttribute(attribute.localName));

        // Do not touch urls with unexpected prefix
        if (match && match[1].indexOf(currentUrlPrefix) === 0) {
          var referenceUrl = encodeUrlForEmbedding(newUrlPrefix + match[1].split(currentUrlPrefix)[1]);
          node.setAttribute(attribute.localName, 'url(' + referenceUrl + ')');
        }
      }
    });
  });
}

/**
 * Because of Firefox bug #353575 gradients and patterns don't work if they are within a symbol.
 * To workaround this we move the gradient definition outside the symbol element
 * @see https://bugzilla.mozilla.org/show_bug.cgi?id=353575
 * @param {Element} svg
 */
var FirefoxSymbolBugWorkaround = function (svg) {
  var defs = svg.querySelector('defs');

  var moveToDefsElems = svg.querySelectorAll('symbol linearGradient, symbol radialGradient, symbol pattern');
  for (var i = 0, len = moveToDefsElems.length; i < len; i++) {
    defs.appendChild(moveToDefsElems[i]);
  }
};

/**
 * @type {string}
 */
var DEFAULT_URI_PREFIX = '#';

/**
 * @type {string}
 */
var xLinkHref = 'xlink:href';
/**
 * @type {string}
 */
var xLinkNS = 'http://www.w3.org/1999/xlink';
/**
 * @type {string}
 */
var svgOpening = '<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="' + xLinkNS + '"';
/**
 * @type {string}
 */
var svgClosing = '</svg>';
/**
 * @type {string}
 */
var contentPlaceHolder = '{content}';

/**
 * Representation of SVG sprite
 * @constructor
 */
function Sprite() {
  var baseElement = document.getElementsByTagName('base')[0];
  var currentUrl = window.location.href.split('#')[0];
  var baseUrl = baseElement && baseElement.href;
  this.urlPrefix = baseUrl && baseUrl !== currentUrl ? currentUrl + DEFAULT_URI_PREFIX : DEFAULT_URI_PREFIX;

  this.content = [];
  this.isFirefox = /firefox\//i.test(navigator.userAgent);
  this.isIE = /(trident|edge)\//i.test(navigator.userAgent);

  if (!this.isIE && baseUrl) {
    window.addEventListener('spriteLoaderLocationUpdated', function (e) {
      var currentPrefix = this.urlPrefix;
      var newUrlPrefix = e.detail.newUrl.split(DEFAULT_URI_PREFIX)[0] + DEFAULT_URI_PREFIX;
      baseUrlWorkAround(this.svg, currentPrefix, newUrlPrefix);
      this.urlPrefix = newUrlPrefix;

      if (this.isFirefox) {
        var nodes = arrayFrom(document.querySelectorAll('use[*|href]'));
        nodes.forEach(function (node) {
          var href = node.getAttribute(xLinkHref);
          if (href && href.indexOf(currentPrefix) === 0) {
            node.setAttributeNS(xLinkNS, xLinkHref, newUrlPrefix + href.split(DEFAULT_URI_PREFIX)[1]);
          }
        });
      }
    }.bind(this));
  }
}

Sprite.styles = ['position:absolute', 'width:0', 'height:0', 'visibility:hidden'];

Sprite.spriteTemplate = svgOpening + ' style="'+ Sprite.styles.join(';') +'"><defs>' + contentPlaceHolder + '</defs>' + svgClosing;
Sprite.symbolTemplate = svgOpening + '>' + contentPlaceHolder + svgClosing;

/**
 * @type {Array<String>}
 */
Sprite.prototype.content = null;

/**
 * @param {String} content
 * @param {String} id
 */
Sprite.prototype.add = function (content, id) {
  if (this.svg) {
    this.appendSymbol(content);
  }

  this.content.push(content);

  return DEFAULT_URI_PREFIX + id;
};

/**
 *
 * @param content
 * @param template
 * @returns {Element}
 */
Sprite.prototype.wrapSVG = function (content, template) {
  var svgString = template.replace(contentPlaceHolder, content);

  var svg = new DOMParser().parseFromString(svgString, 'image/svg+xml').documentElement;

  if (!this.isIE && this.urlPrefix) {
    baseUrlWorkAround(svg, DEFAULT_URI_PREFIX, this.urlPrefix);
  }

  return svg;
};

Sprite.prototype.appendSymbol = function (content) {
  var symbol = this.wrapSVG(content, Sprite.symbolTemplate).childNodes[0];

  this.svg.querySelector('defs').appendChild(symbol);
  if (this.isFirefox) {
    FirefoxSymbolBugWorkaround(this.svg);
  }
};

/**
 * @returns {String}
 */
Sprite.prototype.toString = function () {
  var wrapper = document.createElement('div');
  wrapper.appendChild(this.render());
  return wrapper.innerHTML;
};

/**
 * @param {HTMLElement} [target]
 * @param {Boolean} [prepend=true]
 * @returns {HTMLElement} Rendered sprite node
 */
Sprite.prototype.render = function (target, prepend) {
  target = target || null;
  prepend = typeof prepend === 'boolean' ? prepend : true;

  var svg = this.wrapSVG(this.content.join(''), Sprite.spriteTemplate);

  if (this.isFirefox) {
    FirefoxSymbolBugWorkaround(svg);
  }

  if (target) {
    if (prepend && target.childNodes[0]) {
      target.insertBefore(svg, target.childNodes[0]);
    } else {
      target.appendChild(svg);
    }
  }

  this.svg = svg;

  return svg;
};

module.exports = Sprite;

@@ -857,16 +857,17 @@
 (/%5C(%7C%5C)/
+g
 , %22%5C%5C$&%22

Add "global" flag to brackets matching regexp to replace all brackets but not only the first one