browser-sprite.build.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.BrowserSprite = factory());
  5. }(this, (function () { 'use strict';
  6. var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
  7. function createCommonjsModule(fn, module) {
  8. return module = { exports: {} }, fn(module, module.exports), module.exports;
  9. }
  10. var deepmerge = createCommonjsModule(function (module, exports) {
  11. (function (root, factory) {
  12. if (typeof undefined === 'function' && undefined.amd) {
  13. undefined(factory);
  14. } else {
  15. module.exports = factory();
  16. }
  17. }(commonjsGlobal, function () {
  18. function isMergeableObject(val) {
  19. var nonNullObject = val && typeof val === 'object';
  20. return nonNullObject
  21. && Object.prototype.toString.call(val) !== '[object RegExp]'
  22. && Object.prototype.toString.call(val) !== '[object Date]'
  23. }
  24. function emptyTarget(val) {
  25. return Array.isArray(val) ? [] : {}
  26. }
  27. function cloneIfNecessary(value, optionsArgument) {
  28. var clone = optionsArgument && optionsArgument.clone === true;
  29. return (clone && isMergeableObject(value)) ? deepmerge(emptyTarget(value), value, optionsArgument) : value
  30. }
  31. function defaultArrayMerge(target, source, optionsArgument) {
  32. var destination = target.slice();
  33. source.forEach(function(e, i) {
  34. if (typeof destination[i] === 'undefined') {
  35. destination[i] = cloneIfNecessary(e, optionsArgument);
  36. } else if (isMergeableObject(e)) {
  37. destination[i] = deepmerge(target[i], e, optionsArgument);
  38. } else if (target.indexOf(e) === -1) {
  39. destination.push(cloneIfNecessary(e, optionsArgument));
  40. }
  41. });
  42. return destination
  43. }
  44. function mergeObject(target, source, optionsArgument) {
  45. var destination = {};
  46. if (isMergeableObject(target)) {
  47. Object.keys(target).forEach(function (key) {
  48. destination[key] = cloneIfNecessary(target[key], optionsArgument);
  49. });
  50. }
  51. Object.keys(source).forEach(function (key) {
  52. if (!isMergeableObject(source[key]) || !target[key]) {
  53. destination[key] = cloneIfNecessary(source[key], optionsArgument);
  54. } else {
  55. destination[key] = deepmerge(target[key], source[key], optionsArgument);
  56. }
  57. });
  58. return destination
  59. }
  60. function deepmerge(target, source, optionsArgument) {
  61. var array = Array.isArray(source);
  62. var options = optionsArgument || { arrayMerge: defaultArrayMerge };
  63. var arrayMerge = options.arrayMerge || defaultArrayMerge;
  64. if (array) {
  65. return Array.isArray(target) ? arrayMerge(target, source, optionsArgument) : cloneIfNecessary(source, optionsArgument)
  66. } else {
  67. return mergeObject(target, source, optionsArgument)
  68. }
  69. }
  70. deepmerge.all = function deepmergeAll(array, optionsArgument) {
  71. if (!Array.isArray(array) || array.length < 2) {
  72. throw new Error('first argument should be an array with at least two elements')
  73. }
  74. // we are sure there are at least 2 values, so it is safe to have no initial value
  75. return array.reduce(function(prev, next) {
  76. return deepmerge(prev, next, optionsArgument)
  77. })
  78. };
  79. return deepmerge
  80. }));
  81. });
  82. //
  83. // An event handler can take an optional event argument
  84. // and should not return a value
  85. // An array of all currently registered event handlers for a type
  86. // A map of event types and their corresponding event handlers.
  87. /** Mitt: Tiny (~200b) functional event emitter / pubsub.
  88. * @name mitt
  89. * @returns {Mitt}
  90. */
  91. function mitt(all ) {
  92. all = all || Object.create(null);
  93. return {
  94. /**
  95. * Register an event handler for the given type.
  96. *
  97. * @param {String} type Type of event to listen for, or `"*"` for all events
  98. * @param {Function} handler Function to call in response to given event
  99. * @memberOf mitt
  100. */
  101. on: function on(type , handler ) {
  102. (all[type] || (all[type] = [])).push(handler);
  103. },
  104. /**
  105. * Remove an event handler for the given type.
  106. *
  107. * @param {String} type Type of event to unregister `handler` from, or `"*"`
  108. * @param {Function} handler Handler function to remove
  109. * @memberOf mitt
  110. */
  111. off: function off(type , handler ) {
  112. if (all[type]) {
  113. all[type].splice(all[type].indexOf(handler) >>> 0, 1);
  114. }
  115. },
  116. /**
  117. * Invoke all handlers for the given type.
  118. * If present, `"*"` handlers are invoked after type-matched handlers.
  119. *
  120. * @param {String} type The event type to invoke
  121. * @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
  122. * @memberof mitt
  123. */
  124. emit: function emit(type , evt ) {
  125. (all[type] || []).map(function (handler) { handler(evt); });
  126. (all['*'] || []).map(function (handler) { handler(type, evt); });
  127. }
  128. };
  129. }
  130. var namespaces_1 = createCommonjsModule(function (module, exports) {
  131. var namespaces = {
  132. svg: {
  133. name: 'xmlns',
  134. uri: 'http://www.w3.org/2000/svg'
  135. },
  136. xlink: {
  137. name: 'xmlns:xlink',
  138. uri: 'http://www.w3.org/1999/xlink'
  139. }
  140. };
  141. exports.default = namespaces;
  142. module.exports = exports.default;
  143. });
  144. /**
  145. * @param {Object} attrs
  146. * @return {string}
  147. */
  148. var objectToAttrsString = function (attrs) {
  149. return Object.keys(attrs).map(function (attr) {
  150. var value = attrs[attr].toString().replace(/"/g, '&quot;');
  151. return (attr + "=\"" + value + "\"");
  152. }).join(' ');
  153. };
  154. var svg = namespaces_1.svg;
  155. var xlink = namespaces_1.xlink;
  156. var defaultAttrs = {};
  157. defaultAttrs[svg.name] = svg.uri;
  158. defaultAttrs[xlink.name] = xlink.uri;
  159. /**
  160. * @param {string} [content]
  161. * @param {Object} [attributes]
  162. * @return {string}
  163. */
  164. var wrapInSvgString = function (content, attributes) {
  165. if ( content === void 0 ) content = '';
  166. var attrs = deepmerge(defaultAttrs, attributes || {});
  167. var attrsRendered = objectToAttrsString(attrs);
  168. return ("<svg " + attrsRendered + ">" + content + "</svg>");
  169. };
  170. var svg$1 = namespaces_1.svg;
  171. var xlink$1 = namespaces_1.xlink;
  172. var defaultConfig = {
  173. attrs: ( obj = {
  174. style: ['position: absolute', 'width: 0', 'height: 0'].join('; ')
  175. }, obj[svg$1.name] = svg$1.uri, obj[xlink$1.name] = xlink$1.uri, obj )
  176. };
  177. var obj;
  178. var Sprite = function Sprite(config) {
  179. this.config = deepmerge(defaultConfig, config || {});
  180. this.symbols = [];
  181. };
  182. /**
  183. * Add new symbol. If symbol with the same id exists it will be replaced.
  184. * @param {SpriteSymbol} symbol
  185. * @return {boolean} `true` - symbol was added, `false` - replaced
  186. */
  187. Sprite.prototype.add = function add (symbol) {
  188. var ref = this;
  189. var symbols = ref.symbols;
  190. var existing = this.find(symbol.id);
  191. if (existing) {
  192. symbols[symbols.indexOf(existing)] = symbol;
  193. return false;
  194. }
  195. symbols.push(symbol);
  196. return true;
  197. };
  198. /**
  199. * Remove symbol & destroy it
  200. * @param {string} id
  201. * @return {boolean} `true` - symbol was found & successfully destroyed, `false` - otherwise
  202. */
  203. Sprite.prototype.remove = function remove (id) {
  204. var ref = this;
  205. var symbols = ref.symbols;
  206. var symbol = this.find(id);
  207. if (symbol) {
  208. symbols.splice(symbols.indexOf(symbol), 1);
  209. symbol.destroy();
  210. return true;
  211. }
  212. return false;
  213. };
  214. /**
  215. * @param {string} id
  216. * @return {SpriteSymbol|null}
  217. */
  218. Sprite.prototype.find = function find (id) {
  219. return this.symbols.filter(function (s) { return s.id === id; })[0] || null;
  220. };
  221. /**
  222. * @param {string} id
  223. * @return {boolean}
  224. */
  225. Sprite.prototype.has = function has (id) {
  226. return this.find(id) !== null;
  227. };
  228. /**
  229. * @return {string}
  230. */
  231. Sprite.prototype.stringify = function stringify () {
  232. var ref = this.config;
  233. var attrs = ref.attrs;
  234. var stringifiedSymbols = this.symbols.map(function (s) { return s.stringify(); }).join('');
  235. return wrapInSvgString(stringifiedSymbols, attrs);
  236. };
  237. /**
  238. * @return {string}
  239. */
  240. Sprite.prototype.toString = function toString () {
  241. return this.stringify();
  242. };
  243. Sprite.prototype.destroy = function destroy () {
  244. this.symbols.forEach(function (s) { return s.destroy(); });
  245. };
  246. var SpriteSymbol = function SpriteSymbol(ref) {
  247. var id = ref.id;
  248. var viewBox = ref.viewBox;
  249. var content = ref.content;
  250. this.id = id;
  251. this.viewBox = viewBox;
  252. this.content = content;
  253. };
  254. /**
  255. * @return {string}
  256. */
  257. SpriteSymbol.prototype.stringify = function stringify () {
  258. return this.content;
  259. };
  260. /**
  261. * @return {string}
  262. */
  263. SpriteSymbol.prototype.toString = function toString () {
  264. return this.stringify();
  265. };
  266. SpriteSymbol.prototype.destroy = function destroy () {
  267. var this$1 = this;
  268. ['id', 'viewBox', 'content'].forEach(function (prop) { return delete this$1[prop]; });
  269. };
  270. /**
  271. * @param {string} content
  272. * @return {Element}
  273. */
  274. var parse = function (content) {
  275. var hasImportNode = !!document.importNode;
  276. var doc = new DOMParser().parseFromString(content, 'image/svg+xml').documentElement;
  277. /**
  278. * Fix for browser which are throwing WrongDocumentError
  279. * if you insert an element which is not part of the document
  280. * @see http://stackoverflow.com/a/7986519/4624403
  281. */
  282. if (hasImportNode) {
  283. return document.importNode(doc, true);
  284. }
  285. return doc;
  286. };
  287. var BrowserSpriteSymbol = (function (SpriteSymbol$$1) {
  288. function BrowserSpriteSymbol () {
  289. SpriteSymbol$$1.apply(this, arguments);
  290. }
  291. if ( SpriteSymbol$$1 ) BrowserSpriteSymbol.__proto__ = SpriteSymbol$$1;
  292. BrowserSpriteSymbol.prototype = Object.create( SpriteSymbol$$1 && SpriteSymbol$$1.prototype );
  293. BrowserSpriteSymbol.prototype.constructor = BrowserSpriteSymbol;
  294. var prototypeAccessors = { isMounted: {} };
  295. prototypeAccessors.isMounted.get = function () {
  296. return !!this.node;
  297. };
  298. /**
  299. * @param {Element} node
  300. * @return {BrowserSpriteSymbol}
  301. */
  302. BrowserSpriteSymbol.createFromExistingNode = function createFromExistingNode (node) {
  303. return new BrowserSpriteSymbol({
  304. id: node.getAttribute('id'),
  305. viewBox: node.getAttribute('viewBox'),
  306. content: node.outerHTML
  307. });
  308. };
  309. BrowserSpriteSymbol.prototype.destroy = function destroy () {
  310. if (this.isMounted) {
  311. this.unmount();
  312. }
  313. SpriteSymbol$$1.prototype.destroy.call(this);
  314. };
  315. /**
  316. * @param {Element|string} target
  317. * @return {Element}
  318. */
  319. BrowserSpriteSymbol.prototype.mount = function mount (target) {
  320. if (this.isMounted) {
  321. return this.node;
  322. }
  323. var mountTarget = typeof target === 'string' ? document.querySelector(target) : target;
  324. var node = this.render();
  325. this.node = node;
  326. mountTarget.appendChild(node);
  327. return node;
  328. };
  329. /**
  330. * @return {Element}
  331. */
  332. BrowserSpriteSymbol.prototype.render = function render () {
  333. var content = this.stringify();
  334. return parse(wrapInSvgString(content)).childNodes[0];
  335. };
  336. BrowserSpriteSymbol.prototype.unmount = function unmount () {
  337. this.node.parentNode.removeChild(this.node);
  338. };
  339. Object.defineProperties( BrowserSpriteSymbol.prototype, prototypeAccessors );
  340. return BrowserSpriteSymbol;
  341. }(SpriteSymbol));
  342. var defaultConfig$1 = {
  343. /**
  344. * Should following options be automatically configured:
  345. * - `syncUrlsWithBaseTag`
  346. * - `locationChangeAngularEmitter`
  347. * - `moveGradientsOutsideSymbol`
  348. * @type {boolean}
  349. */
  350. autoConfigure: true,
  351. /**
  352. * Default mounting selector
  353. * @type {string}
  354. */
  355. mountTo: 'body',
  356. /**
  357. * Fix disappearing SVG elements when <base href> exists.
  358. * Executes when sprite mounted.
  359. * @see http://stackoverflow.com/a/18265336/796152
  360. * @see https://github.com/everdimension/angular-svg-base-fix
  361. * @see https://github.com/angular/angular.js/issues/8934#issuecomment-56568466
  362. * @type {boolean}
  363. */
  364. syncUrlsWithBaseTag: false,
  365. /**
  366. * Should sprite listen custom location change event
  367. * @type {boolean}
  368. */
  369. listenLocationChangeEvent: true,
  370. /**
  371. * Custom window event name which should be emitted to update sprite urls
  372. * @type {string}
  373. */
  374. locationChangeEvent: 'locationChange',
  375. /**
  376. * Emit location change event in Angular automatically
  377. * @type {boolean}
  378. */
  379. locationChangeAngularEmitter: false,
  380. /**
  381. * Selector to find symbols usages when updating sprite urls
  382. * @type {string}
  383. */
  384. usagesToUpdate: 'use[*|href]',
  385. /**
  386. * Fix Firefox bug when gradients and patterns don't work if they are within a symbol.
  387. * Executes when sprite is rendered, but not mounted.
  388. * @see https://bugzilla.mozilla.org/show_bug.cgi?id=306674
  389. * @see https://bugzilla.mozilla.org/show_bug.cgi?id=353575
  390. * @see https://bugzilla.mozilla.org/show_bug.cgi?id=1235364
  391. * @type {boolean}
  392. */
  393. moveGradientsOutsideSymbol: false
  394. };
  395. /**
  396. * @param {*} arrayLike
  397. * @return {Array}
  398. */
  399. var arrayFrom = function (arrayLike) {
  400. return Array.prototype.slice.call(arrayLike, 0);
  401. };
  402. var ua = navigator.userAgent;
  403. var browser = {
  404. isChrome: /chrome/i.test(ua),
  405. isFirefox: /firefox/i.test(ua),
  406. // https://msdn.microsoft.com/en-us/library/ms537503(v=vs.85).aspx
  407. isIE: /msie/i.test(ua) || /trident/i.test(ua),
  408. isEdge: /edge/i.test(ua)
  409. };
  410. /**
  411. * @param {string} name
  412. * @param {*} data
  413. */
  414. var dispatchEvent = function (name, data) {
  415. var event = document.createEvent('CustomEvent');
  416. event.initCustomEvent(name, false, false, data);
  417. window.dispatchEvent(event);
  418. };
  419. /**
  420. * IE doesn't evaluate <style> tags in SVGs that are dynamically added to the page.
  421. * This trick will trigger IE to read and use any existing SVG <style> tags.
  422. * @see https://github.com/iconic/SVGInjector/issues/23
  423. * @see https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/10898469/
  424. *
  425. * @param {Element} node DOM Element to search <style> tags in
  426. * @return {Array<HTMLStyleElement>}
  427. */
  428. var evalStylesIEWorkaround = function (node) {
  429. var updatedNodes = [];
  430. arrayFrom(node.querySelectorAll('style'))
  431. .forEach(function (style) {
  432. style.textContent += '';
  433. updatedNodes.push(style);
  434. });
  435. return updatedNodes;
  436. };
  437. /**
  438. * @param {string} [url] If not provided - current URL will be used
  439. * @return {string}
  440. */
  441. var getUrlWithoutFragment = function (url) {
  442. return (url || window.location.href).split('#')[0];
  443. };
  444. /* global angular */
  445. /**
  446. * @param {string} eventName
  447. */
  448. var locationChangeAngularEmitter = function (eventName) {
  449. angular.module('ng').run(['$rootScope', function ($rootScope) {
  450. $rootScope.$on('$locationChangeSuccess', function (e, newUrl, oldUrl) {
  451. dispatchEvent(eventName, { oldUrl: oldUrl, newUrl: newUrl });
  452. });
  453. }]);
  454. };
  455. var defaultSelector = 'linearGradient, radialGradient, pattern';
  456. /**
  457. * @param {Element} svg
  458. * @param {string} [selector]
  459. * @return {Element}
  460. */
  461. var moveGradientsOutsideSymbol = function (svg, selector) {
  462. if ( selector === void 0 ) selector = defaultSelector;
  463. arrayFrom(svg.querySelectorAll('symbol')).forEach(function (symbol) {
  464. arrayFrom(symbol.querySelectorAll(selector)).forEach(function (node) {
  465. symbol.parentNode.insertBefore(node, symbol);
  466. });
  467. });
  468. return svg;
  469. };
  470. /**
  471. * @param {NodeList} nodes
  472. * @param {Function} [matcher]
  473. * @return {Attr[]}
  474. */
  475. function selectAttributes(nodes, matcher) {
  476. var attrs = arrayFrom(nodes).reduce(function (acc, node) {
  477. if (!node.attributes) {
  478. return acc;
  479. }
  480. var arrayfied = arrayFrom(node.attributes);
  481. var matched = matcher ? arrayfied.filter(matcher) : arrayfied;
  482. return acc.concat(matched);
  483. }, []);
  484. return attrs;
  485. }
  486. /**
  487. * @param {NodeList|Node} nodes
  488. * @param {boolean} [clone=true]
  489. * @return {string}
  490. */
  491. var xLinkNS = namespaces_1.xlink.uri;
  492. var xLinkAttrName = 'xlink:href';
  493. // eslint-disable-next-line no-useless-escape
  494. var specialUrlCharsPattern = /[{}|\\\^\[\]`"<>]/g;
  495. function encoder(url) {
  496. return url.replace(specialUrlCharsPattern, function (match) {
  497. return ("%" + (match[0].charCodeAt(0).toString(16).toUpperCase()));
  498. });
  499. }
  500. /**
  501. * @param {NodeList} nodes
  502. * @param {string} startsWith
  503. * @param {string} replaceWith
  504. * @return {NodeList}
  505. */
  506. function updateReferences(nodes, startsWith, replaceWith) {
  507. arrayFrom(nodes).forEach(function (node) {
  508. var href = node.getAttribute(xLinkAttrName);
  509. if (href && href.indexOf(startsWith) === 0) {
  510. var newUrl = href.replace(startsWith, replaceWith);
  511. node.setAttributeNS(xLinkNS, xLinkAttrName, newUrl);
  512. }
  513. });
  514. return nodes;
  515. }
  516. /**
  517. * List of SVG attributes to update url() target in them
  518. */
  519. var attList = [
  520. 'clipPath',
  521. 'colorProfile',
  522. 'src',
  523. 'cursor',
  524. 'fill',
  525. 'filter',
  526. 'marker',
  527. 'markerStart',
  528. 'markerMid',
  529. 'markerEnd',
  530. 'mask',
  531. 'stroke',
  532. 'style'
  533. ];
  534. var attSelector = attList.map(function (attr) { return ("[" + attr + "]"); }).join(',');
  535. /**
  536. * Update URLs in svg image (like `fill="url(...)"`) and update referencing elements
  537. * @param {Element} svg
  538. * @param {NodeList} references
  539. * @param {string|RegExp} startsWith
  540. * @param {string} replaceWith
  541. * @return {void}
  542. *
  543. * @example
  544. * const sprite = document.querySelector('svg.sprite');
  545. * const usages = document.querySelectorAll('use');
  546. * updateUrls(sprite, usages, '#', 'prefix#');
  547. */
  548. var updateUrls = function (svg, references, startsWith, replaceWith) {
  549. var startsWithEncoded = encoder(startsWith);
  550. var replaceWithEncoded = encoder(replaceWith);
  551. var nodes = svg.querySelectorAll(attSelector);
  552. var attrs = selectAttributes(nodes, function (ref) {
  553. var localName = ref.localName;
  554. var value = ref.value;
  555. return attList.indexOf(localName) !== -1 && value.indexOf(("url(" + startsWithEncoded)) !== -1;
  556. });
  557. attrs.forEach(function (attr) { return attr.value = attr.value.replace(startsWithEncoded, replaceWithEncoded); });
  558. updateReferences(references, startsWithEncoded, replaceWithEncoded);
  559. };
  560. /**
  561. * Internal emitter events
  562. * @enum
  563. * @private
  564. */
  565. var Events = {
  566. MOUNT: 'mount',
  567. SYMBOL_MOUNT: 'symbol_mount'
  568. };
  569. var BrowserSprite = (function (Sprite$$1) {
  570. function BrowserSprite(cfg) {
  571. var this$1 = this;
  572. if ( cfg === void 0 ) cfg = {};
  573. Sprite$$1.call(this, deepmerge(defaultConfig$1, cfg));
  574. var emitter = mitt();
  575. this._emitter = emitter;
  576. this.node = null;
  577. var ref = this;
  578. var config = ref.config;
  579. if (config.autoConfigure) {
  580. this._autoConfigure(cfg);
  581. }
  582. if (config.syncUrlsWithBaseTag) {
  583. var baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
  584. emitter.on(Events.MOUNT, function () { return this$1.updateUrls('#', baseUrl); });
  585. }
  586. var handleLocationChange = this._handleLocationChange.bind(this);
  587. this._handleLocationChange = handleLocationChange;
  588. // Provide way to update sprite urls externally via dispatching custom window event
  589. if (config.listenLocationChangeEvent) {
  590. window.addEventListener(config.locationChangeEvent, handleLocationChange);
  591. }
  592. // Emit location change event in Angular automatically
  593. if (config.locationChangeAngularEmitter) {
  594. locationChangeAngularEmitter(config.locationChangeEvent);
  595. }
  596. // After sprite mounted
  597. emitter.on(Events.MOUNT, function (spriteNode) {
  598. if (config.moveGradientsOutsideSymbol) {
  599. moveGradientsOutsideSymbol(spriteNode);
  600. }
  601. });
  602. // After symbol mounted into sprite
  603. emitter.on(Events.SYMBOL_MOUNT, function (symbolNode) {
  604. if (config.moveGradientsOutsideSymbol) {
  605. moveGradientsOutsideSymbol(symbolNode.parentNode);
  606. }
  607. if (browser.isIE || browser.isEdge) {
  608. evalStylesIEWorkaround(symbolNode);
  609. }
  610. });
  611. }
  612. if ( Sprite$$1 ) BrowserSprite.__proto__ = Sprite$$1;
  613. BrowserSprite.prototype = Object.create( Sprite$$1 && Sprite$$1.prototype );
  614. BrowserSprite.prototype.constructor = BrowserSprite;
  615. var prototypeAccessors = { isMounted: {} };
  616. /**
  617. * @return {boolean}
  618. */
  619. prototypeAccessors.isMounted.get = function () {
  620. return !!this.node;
  621. };
  622. /**
  623. * Automatically configure following options
  624. * - `syncUrlsWithBaseTag`
  625. * - `locationChangeAngularEmitter`
  626. * - `moveGradientsOutsideSymbol`
  627. * @param {Object} cfg
  628. * @private
  629. */
  630. BrowserSprite.prototype._autoConfigure = function _autoConfigure (cfg) {
  631. var ref = this;
  632. var config = ref.config;
  633. if (typeof cfg.syncUrlsWithBaseTag === 'undefined') {
  634. config.syncUrlsWithBaseTag = typeof document.getElementsByTagName('base')[0] !== 'undefined';
  635. }
  636. if (typeof cfg.locationChangeAngularEmitter === 'undefined') {
  637. config.locationChangeAngularEmitter = 'angular' in window;
  638. }
  639. if (typeof cfg.moveGradientsOutsideSymbol === 'undefined') {
  640. config.moveGradientsOutsideSymbol = browser.isFirefox;
  641. }
  642. };
  643. /**
  644. * @param {Event} event
  645. * @param {Object} event.detail
  646. * @param {string} event.detail.oldUrl
  647. * @param {string} event.detail.newUrl
  648. * @private
  649. */
  650. BrowserSprite.prototype._handleLocationChange = function _handleLocationChange (event) {
  651. var ref = event.detail;
  652. var oldUrl = ref.oldUrl;
  653. var newUrl = ref.newUrl;
  654. this.updateUrls(oldUrl, newUrl);
  655. };
  656. /**
  657. * Add new symbol. If symbol with the same id exists it will be replaced.
  658. * If sprite already mounted - `symbol.mount(sprite.node)` will be called.
  659. * @fires Events#SYMBOL_MOUNT
  660. * @param {BrowserSpriteSymbol} symbol
  661. * @return {boolean} `true` - symbol was added, `false` - replaced
  662. */
  663. BrowserSprite.prototype.add = function add (symbol) {
  664. var sprite = this;
  665. var isNewSymbol = Sprite$$1.prototype.add.call(this, symbol);
  666. if (this.isMounted && isNewSymbol) {
  667. symbol.mount(sprite.node);
  668. this._emitter.emit(Events.SYMBOL_MOUNT, symbol.node);
  669. }
  670. return isNewSymbol;
  671. };
  672. /**
  673. * Attach to existing DOM node
  674. * @param {string|Element} target
  675. * @return {Element|null} attached DOM Element. null if node to attach not found.
  676. */
  677. BrowserSprite.prototype.attach = function attach (target) {
  678. var this$1 = this;
  679. var sprite = this;
  680. if (sprite.isMounted) {
  681. return sprite.node;
  682. }
  683. /** @type Element */
  684. var node = typeof target === 'string' ? document.querySelector(target) : target;
  685. sprite.node = node;
  686. // Already added symbols needs to be mounted
  687. this.symbols.forEach(function (symbol) {
  688. symbol.mount(sprite.node);
  689. this$1._emitter.emit(Events.SYMBOL_MOUNT, symbol.node);
  690. });
  691. // Create symbols from existing DOM nodes, add and mount them
  692. arrayFrom(node.querySelectorAll('symbol'))
  693. .forEach(function (symbolNode) {
  694. var symbol = BrowserSpriteSymbol.createFromExistingNode(symbolNode);
  695. symbol.node = symbolNode; // hack to prevent symbol mounting to sprite when adding
  696. sprite.add(symbol);
  697. });
  698. this._emitter.emit(Events.MOUNT, node);
  699. return node;
  700. };
  701. BrowserSprite.prototype.destroy = function destroy () {
  702. var ref = this;
  703. var config = ref.config;
  704. var symbols = ref.symbols;
  705. var _emitter = ref._emitter;
  706. symbols.forEach(function (s) { return s.destroy(); });
  707. _emitter.off('*');
  708. window.removeEventListener(config.locationChangeEvent, this._handleLocationChange);
  709. if (this.isMounted) {
  710. this.unmount();
  711. }
  712. };
  713. /**
  714. * @fires Events#MOUNT
  715. * @param {string|Element} [target]
  716. * @param {boolean} [prepend=false]
  717. * @return {Element|null} rendered sprite node. null if mount node not found.
  718. */
  719. BrowserSprite.prototype.mount = function mount (target, prepend) {
  720. if ( target === void 0 ) target = this.config.mountTo;
  721. if ( prepend === void 0 ) prepend = false;
  722. var sprite = this;
  723. if (sprite.isMounted) {
  724. return sprite.node;
  725. }
  726. var mountNode = typeof target === 'string' ? document.querySelector(target) : target;
  727. var node = sprite.render();
  728. this.node = node;
  729. if (prepend && mountNode.childNodes[0]) {
  730. mountNode.insertBefore(node, mountNode.childNodes[0]);
  731. } else {
  732. mountNode.appendChild(node);
  733. }
  734. this._emitter.emit(Events.MOUNT, node);
  735. return node;
  736. };
  737. /**
  738. * @return {Element}
  739. */
  740. BrowserSprite.prototype.render = function render () {
  741. return parse(this.stringify());
  742. };
  743. /**
  744. * Detach sprite from the DOM
  745. */
  746. BrowserSprite.prototype.unmount = function unmount () {
  747. this.node.parentNode.removeChild(this.node);
  748. };
  749. /**
  750. * Update URLs in sprite and usage elements
  751. * @param {string} oldUrl
  752. * @param {string} newUrl
  753. * @return {boolean} `true` - URLs was updated, `false` - sprite is not mounted
  754. */
  755. BrowserSprite.prototype.updateUrls = function updateUrls$1 (oldUrl, newUrl) {
  756. if (!this.isMounted) {
  757. return false;
  758. }
  759. var usages = document.querySelectorAll(this.config.usagesToUpdate);
  760. updateUrls(
  761. this.node,
  762. usages,
  763. ((getUrlWithoutFragment(oldUrl)) + "#"),
  764. ((getUrlWithoutFragment(newUrl)) + "#")
  765. );
  766. return true;
  767. };
  768. Object.defineProperties( BrowserSprite.prototype, prototypeAccessors );
  769. return BrowserSprite;
  770. }(Sprite));
  771. var ready$1 = createCommonjsModule(function (module) {
  772. /*!
  773. * domready (c) Dustin Diaz 2014 - License MIT
  774. */
  775. !function (name, definition) {
  776. { module.exports = definition(); }
  777. }('domready', function () {
  778. var fns = [], listener
  779. , doc = document
  780. , hack = doc.documentElement.doScroll
  781. , domContentLoaded = 'DOMContentLoaded'
  782. , loaded = (hack ? /^loaded|^c/ : /^loaded|^i|^c/).test(doc.readyState);
  783. if (!loaded)
  784. { doc.addEventListener(domContentLoaded, listener = function () {
  785. doc.removeEventListener(domContentLoaded, listener);
  786. loaded = 1;
  787. while (listener = fns.shift()) { listener(); }
  788. }); }
  789. return function (fn) {
  790. loaded ? setTimeout(fn, 0) : fns.push(fn);
  791. }
  792. });
  793. });
  794. var spriteNodeId = '__SVG_SPRITE_NODE__';
  795. var spriteGlobalVarName = '__SVG_SPRITE__';
  796. var isSpriteExists = !!window[spriteGlobalVarName];
  797. // eslint-disable-next-line import/no-mutable-exports
  798. var sprite;
  799. if (isSpriteExists) {
  800. sprite = window[spriteGlobalVarName];
  801. } else {
  802. sprite = new BrowserSprite({ attrs: { id: spriteNodeId } });
  803. window[spriteGlobalVarName] = sprite;
  804. }
  805. var loadSprite = function () {
  806. /**
  807. * Check for page already contains sprite node
  808. * If found - attach to and reuse it's content
  809. * If not - render and mount the new sprite
  810. */
  811. var existing = document.getElementById(spriteNodeId);
  812. if (existing) {
  813. sprite.attach(existing);
  814. } else {
  815. sprite.mount(document.body, true);
  816. }
  817. };
  818. if (document.body) {
  819. loadSprite();
  820. } else {
  821. ready$1(loadSprite);
  822. }
  823. var sprite$1 = sprite;
  824. return sprite$1;
  825. })));