unvendor: Replace SVGInject

8b8f2f1144bf3b27e15306d65368fc3cde9bace7

Cohee <18619528+Cohee1207@users.noreply.github.com>

8 files changed, +17 -701Ignore whitespace
.eslintrc.cjs+0 -1
@@ -55,7 +55,6 @@ module.exports = {
55 Popper: 'readonly',55 Popper: 'readonly',
56 showdown: 'readonly',56 showdown: 'readonly',
57 showdownKatex: 'readonly',57 showdownKatex: 'readonly',
58 SVGInject: 'readonly',
59 toastr: 'readonly',58 toastr: 'readonly',
60 isProbablyReaderable: 'readonly',59 isProbablyReaderable: 'readonly',
61 SillyTavern: 'readonly',60 SillyTavern: 'readonly',
package-lock.json+7 -0
@@ -13,6 +13,7 @@
13 "@adobe/css-tools": "^4.4.0",13 "@adobe/css-tools": "^4.4.0",
14 "@agnai/sentencepiece-js": "^1.1.1",14 "@agnai/sentencepiece-js": "^1.1.1",
15 "@agnai/web-tokenizers": "^0.1.3",15 "@agnai/web-tokenizers": "^0.1.3",
16 "@iconfu/svg-inject": "^1.2.3",
16 "@mozilla/readability": "^0.5.0",17 "@mozilla/readability": "^0.5.0",
17 "@zeldafan0225/ai_horde": "^5.1.0",18 "@zeldafan0225/ai_horde": "^5.1.0",
18 "archiver": "^7.0.1",19 "archiver": "^7.0.1",
@@ -287,6 +288,12 @@
287 "dev": true,288 "dev": true,
288 "license": "BSD-3-Clause"289 "license": "BSD-3-Clause"
289 },290 },
291 "node_modules/@iconfu/svg-inject": {
292 "version": "1.2.3",
293 "resolved": "https://registry.npmjs.org/@iconfu/svg-inject/-/svg-inject-1.2.3.tgz",
294 "integrity": "sha512-3v1MUAJqmJS4jmhHoCkSxt+EdJrjPHlLXrWocCT25kCxnxJto8028Z6CC406EL11KA53SDZgI/QQA5GEJAoiRw==",
295 "license": "MIT"
296 },
290 "node_modules/@isaacs/cliui": {297 "node_modules/@isaacs/cliui": {
291 "version": "8.0.2",298 "version": "8.0.2",
292 "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",299 "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
package.json+1 -0
@@ -3,6 +3,7 @@
3 "@adobe/css-tools": "^4.4.0",3 "@adobe/css-tools": "^4.4.0",
4 "@agnai/sentencepiece-js": "^1.1.1",4 "@agnai/sentencepiece-js": "^1.1.1",
5 "@agnai/web-tokenizers": "^0.1.3",5 "@agnai/web-tokenizers": "^0.1.3",
6 "@iconfu/svg-inject": "^1.2.3",
6 "@mozilla/readability": "^0.5.0",7 "@mozilla/readability": "^0.5.0",
7 "@zeldafan0225/ai_horde": "^5.1.0",8 "@zeldafan0225/ai_horde": "^5.1.0",
8 "archiver": "^7.0.1",9 "archiver": "^7.0.1",
public/global.d.ts+0 -1
@@ -3,7 +3,6 @@ declare var droll;
3declare var Popper;3declare var Popper;
4declare var showdown;4declare var showdown;
5declare var showdownKatex;5declare var showdownKatex;
6declare var SVGInject;
7declare var ai;6declare var ai;
87
9declare var SillyTavern: {8declare var SillyTavern: {
public/index.html+0 -1
@@ -6759,7 +6759,6 @@
6759 <script src="lib/droll.js"></script>6759 <script src="lib/droll.js"></script>
6760 <script src="lib/pagination.js"></script>6760 <script src="lib/pagination.js"></script>
6761 <script src="lib/toolcool-color-picker.js"></script>6761 <script src="lib/toolcool-color-picker.js"></script>
6762 <script src="lib/svg-inject.js"></script>
6763 <script src="lib/jquery.izoomify.js"></script>6762 <script src="lib/jquery.izoomify.js"></script>
6764 <script type="module" src="lib/structured-clone/monkey-patch.js"></script>6763 <script type="module" src="lib/structured-clone/monkey-patch.js"></script>
6765 <script type="module" src="lib/swiped-events.js"></script>6764 <script type="module" src="lib/swiped-events.js"></script>
public/lib.js+7 -0
@@ -14,6 +14,7 @@ import ePub from 'epubjs';
14import * as pdfjsLib from 'pdfjs-dist/webpack.mjs';14import * as pdfjsLib from 'pdfjs-dist/webpack.mjs';
15import DiffMatchPatch from 'diff-match-patch';15import DiffMatchPatch from 'diff-match-patch';
16import { isProbablyReaderable, Readability } from '@mozilla/readability';16import { isProbablyReaderable, Readability } from '@mozilla/readability';
17import SVGInject from '@iconfu/svg-inject';
1718
18/**19/**
19 * Expose the libraries to the 'window' object.20 * Expose the libraries to the 'window' object.
@@ -48,6 +49,10 @@ export function initLibraryShims() {
48 // @ts-ignore49 // @ts-ignore
49 window.diff_match_patch = DiffMatchPatch;50 window.diff_match_patch = DiffMatchPatch;
50 }51 }
52 if (!('SVGInject' in window)) {
53 // @ts-ignore
54 window.SVGInject = SVGInject;
55 }
51}56}
5257
53export default {58export default {
@@ -64,6 +69,7 @@ export default {
64 DiffMatchPatch,69 DiffMatchPatch,
65 Readability,70 Readability,
66 isProbablyReaderable,71 isProbablyReaderable,
72 SVGInject,
67};73};
6874
69export {75export {
@@ -80,4 +86,5 @@ export {
80 DiffMatchPatch,86 DiffMatchPatch,
81 Readability,87 Readability,
82 isProbablyReaderable,88 isProbablyReaderable,
89 SVGInject,
83};90};
public/lib/svg-inject.js+0 -697
@@ -1,697 +0,0 @@
1/**
2 * SVGInject - Version 1.2.3
3 * A tiny, intuitive, robust, caching solution for injecting SVG files inline into the DOM.
4 *
5 * https://github.com/iconfu/svg-inject
6 *
7 * Copyright (c) 2018 INCORS, the creators of iconfu.com
8 * @license MIT License - https://github.com/iconfu/svg-inject/blob/master/LICENSE
9 */
10
11(function(window, document) {
12 // constants for better minification
13 var _CREATE_ELEMENT_ = 'createElement';
14 var _GET_ELEMENTS_BY_TAG_NAME_ = 'getElementsByTagName';
15 var _LENGTH_ = 'length';
16 var _STYLE_ = 'style';
17 var _TITLE_ = 'title';
18 var _UNDEFINED_ = 'undefined';
19 var _SET_ATTRIBUTE_ = 'setAttribute';
20 var _GET_ATTRIBUTE_ = 'getAttribute';
21
22 var NULL = null;
23
24 // constants
25 var __SVGINJECT = '__svgInject';
26 var ID_SUFFIX = '--inject-';
27 var ID_SUFFIX_REGEX = new RegExp(ID_SUFFIX + '\\d+', "g");
28 var LOAD_FAIL = 'LOAD_FAIL';
29 var SVG_NOT_SUPPORTED = 'SVG_NOT_SUPPORTED';
30 var SVG_INVALID = 'SVG_INVALID';
31 var ATTRIBUTE_EXCLUSION_NAMES = ['src', 'alt', 'onload', 'onerror'];
32 var A_ELEMENT = document[_CREATE_ELEMENT_]('a');
33 var IS_SVG_SUPPORTED = typeof SVGRect != _UNDEFINED_;
34 var DEFAULT_OPTIONS = {
35 useCache: true,
36 copyAttributes: true,
37 makeIdsUnique: true
38 };
39 // Map of IRI referenceable tag names to properties that can reference them. This is defined in
40 // https://www.w3.org/TR/SVG11/linking.html#processingIRI
41 var IRI_TAG_PROPERTIES_MAP = {
42 clipPath: ['clip-path'],
43 'color-profile': NULL,
44 cursor: NULL,
45 filter: NULL,
46 linearGradient: ['fill', 'stroke'],
47 marker: ['marker', 'marker-end', 'marker-mid', 'marker-start'],
48 mask: NULL,
49 pattern: ['fill', 'stroke'],
50 radialGradient: ['fill', 'stroke']
51 };
52 var INJECTED = 1;
53 var FAIL = 2;
54
55 var uniqueIdCounter = 1;
56 var xmlSerializer;
57 var domParser;
58
59
60 // creates an SVG document from an SVG string
61 function svgStringToSvgDoc(svgStr) {
62 domParser = domParser || new DOMParser();
63 return domParser.parseFromString(svgStr, 'text/xml');
64 }
65
66
67 // searializes an SVG element to an SVG string
68 function svgElemToSvgString(svgElement) {
69 xmlSerializer = xmlSerializer || new XMLSerializer();
70 return xmlSerializer.serializeToString(svgElement);
71 }
72
73
74 // Returns the absolute url for the specified url
75 function getAbsoluteUrl(url) {
76 A_ELEMENT.href = url;
77 return A_ELEMENT.href;
78 }
79
80
81 // Load svg with an XHR request
82 function loadSvg(url, callback, errorCallback) {
83 if (url) {
84 var req = new XMLHttpRequest();
85 req.onreadystatechange = function() {
86 if (req.readyState == 4) {
87 // readyState is DONE
88 var status = req.status;
89 if (status == 200) {
90 // request status is OK
91 callback(req.responseXML, req.responseText.trim());
92 } else if (status >= 400) {
93 // request status is error (4xx or 5xx)
94 errorCallback();
95 } else if (status == 0) {
96 // request status 0 can indicate a failed cross-domain call
97 errorCallback();
98 }
99 }
100 };
101 req.open('GET', url, true);
102 req.send();
103 }
104 }
105
106
107 // Copy attributes from img element to svg element
108 function copyAttributes(imgElem, svgElem) {
109 var attribute;
110 var attributeName;
111 var attributeValue;
112 var attributes = imgElem.attributes;
113 for (var i = 0; i < attributes[_LENGTH_]; i++) {
114 attribute = attributes[i];
115 attributeName = attribute.name;
116 // Only copy attributes not explicitly excluded from copying
117 if (ATTRIBUTE_EXCLUSION_NAMES.indexOf(attributeName) == -1) {
118 attributeValue = attribute.value;
119 // If img attribute is "title", insert a title element into SVG element
120 if (attributeName == _TITLE_) {
121 var titleElem;
122 var firstElementChild = svgElem.firstElementChild;
123 if (firstElementChild && firstElementChild.localName.toLowerCase() == _TITLE_) {
124 // If the SVG element's first child is a title element, keep it as the title element
125 titleElem = firstElementChild;
126 } else {
127 // If the SVG element's first child element is not a title element, create a new title
128 // ele,emt and set it as the first child
129 titleElem = document[_CREATE_ELEMENT_ + 'NS']('http://www.w3.org/2000/svg', _TITLE_);
130 svgElem.insertBefore(titleElem, firstElementChild);
131 }
132 // Set new title content
133 titleElem.textContent = attributeValue;
134 } else {
135 // Set img attribute to svg element
136 svgElem[_SET_ATTRIBUTE_](attributeName, attributeValue);
137 }
138 }
139 }
140 }
141
142
143 // This function appends a suffix to IDs of referenced elements in the <defs> in order to to avoid ID collision
144 // between multiple injected SVGs. The suffix has the form "--inject-X", where X is a running number which is
145 // incremented with each injection. References to the IDs are adjusted accordingly.
146 // We assume tha all IDs within the injected SVG are unique, therefore the same suffix can be used for all IDs of one
147 // injected SVG.
148 // If the onlyReferenced argument is set to true, only those IDs will be made unique that are referenced from within the SVG
149 function makeIdsUnique(svgElem, onlyReferenced) {
150 var idSuffix = ID_SUFFIX + uniqueIdCounter++;
151 // Regular expression for functional notations of an IRI references. This will find occurences in the form
152 // url(#anyId) or url("#anyId") (for Internet Explorer) and capture the referenced ID
153 var funcIriRegex = /url\("?#([a-zA-Z][\w:.-]*)"?\)/g;
154 // Get all elements with an ID. The SVG spec recommends to put referenced elements inside <defs> elements, but
155 // this is not a requirement, therefore we have to search for IDs in the whole SVG.
156 var idElements = svgElem.querySelectorAll('[id]');
157 var idElem;
158 // An object containing referenced IDs as keys is used if only referenced IDs should be uniquified.
159 // If this object does not exist, all IDs will be uniquified.
160 var referencedIds = onlyReferenced ? [] : NULL;
161 var tagName;
162 var iriTagNames = {};
163 var iriProperties = [];
164 var changed = false;
165 var i, j;
166
167 if (idElements[_LENGTH_]) {
168 // Make all IDs unique by adding the ID suffix and collect all encountered tag names
169 // that are IRI referenceable from properities.
170 for (i = 0; i < idElements[_LENGTH_]; i++) {
171 tagName = idElements[i].localName; // Use non-namespaced tag name
172 // Make ID unique if tag name is IRI referenceable
173 if (tagName in IRI_TAG_PROPERTIES_MAP) {
174 iriTagNames[tagName] = 1;
175 }
176 }
177 // Get all properties that are mapped to the found IRI referenceable tags
178 for (tagName in iriTagNames) {
179 (IRI_TAG_PROPERTIES_MAP[tagName] || [tagName]).forEach(function (mappedProperty) {
180 // Add mapped properties to array of iri referencing properties.
181 // Use linear search here because the number of possible entries is very small (maximum 11)
182 if (iriProperties.indexOf(mappedProperty) < 0) {
183 iriProperties.push(mappedProperty);
184 }
185 });
186 }
187 if (iriProperties[_LENGTH_]) {
188 // Add "style" to properties, because it may contain references in the form 'style="fill:url(#myFill)"'
189 iriProperties.push(_STYLE_);
190 }
191 // Run through all elements of the SVG and replace IDs in references.
192 // To get all descending elements, getElementsByTagName('*') seems to perform faster than querySelectorAll('*').
193 // Since svgElem.getElementsByTagName('*') does not return the svg element itself, we have to handle it separately.
194 var descElements = svgElem[_GET_ELEMENTS_BY_TAG_NAME_]('*');
195 var element = svgElem;
196 var propertyName;
197 var value;
198 var newValue;
199 for (i = -1; element != NULL;) {
200 if (element.localName == _STYLE_) {
201 // If element is a style element, replace IDs in all occurences of "url(#anyId)" in text content
202 value = element.textContent;
203 newValue = value && value.replace(funcIriRegex, function(match, id) {
204 if (referencedIds) {
205 referencedIds[id] = 1;
206 }
207 return 'url(#' + id + idSuffix + ')';
208 });
209 if (newValue !== value) {
210 element.textContent = newValue;
211 }
212 } else if (element.hasAttributes()) {
213 // Run through all property names for which IDs were found
214 for (j = 0; j < iriProperties[_LENGTH_]; j++) {
215 propertyName = iriProperties[j];
216 value = element[_GET_ATTRIBUTE_](propertyName);
217 newValue = value && value.replace(funcIriRegex, function(match, id) {
218 if (referencedIds) {
219 referencedIds[id] = 1;
220 }
221 return 'url(#' + id + idSuffix + ')';
222 });
223 if (newValue !== value) {
224 element[_SET_ATTRIBUTE_](propertyName, newValue);
225 }
226 }
227 // Replace IDs in xlink:ref and href attributes
228 ['xlink:href', 'href'].forEach(function(refAttrName) {
229 var iri = element[_GET_ATTRIBUTE_](refAttrName);
230 if (/^\s*#/.test(iri)) { // Check if iri is non-null and internal reference
231 iri = iri.trim();
232 element[_SET_ATTRIBUTE_](refAttrName, iri + idSuffix);
233 if (referencedIds) {
234 // Add ID to referenced IDs
235 referencedIds[iri.substring(1)] = 1;
236 }
237 }
238 });
239 }
240 element = descElements[++i];
241 }
242 for (i = 0; i < idElements[_LENGTH_]; i++) {
243 idElem = idElements[i];
244 // If set of referenced IDs exists, make only referenced IDs unique,
245 // otherwise make all IDs unique.
246 if (!referencedIds || referencedIds[idElem.id]) {
247 // Add suffix to element's ID
248 idElem.id += idSuffix;
249 changed = true;
250 }
251 }
252 }
253 // return true if SVG element has changed
254 return changed;
255 }
256
257
258 // For cached SVGs the IDs are made unique by simply replacing the already inserted unique IDs with a
259 // higher ID counter. This is much more performant than a call to makeIdsUnique().
260 function makeIdsUniqueCached(svgString) {
261 return svgString.replace(ID_SUFFIX_REGEX, ID_SUFFIX + uniqueIdCounter++);
262 }
263
264
265 // Inject SVG by replacing the img element with the SVG element in the DOM
266 function inject(imgElem, svgElem, absUrl, options) {
267 if (svgElem) {
268 svgElem[_SET_ATTRIBUTE_]('data-inject-url', absUrl);
269 var parentNode = imgElem.parentNode;
270 if (parentNode) {
271 if (options.copyAttributes) {
272 copyAttributes(imgElem, svgElem);
273 }
274 // Invoke beforeInject hook if set
275 var beforeInject = options.beforeInject;
276 var injectElem = (beforeInject && beforeInject(imgElem, svgElem)) || svgElem;
277 // Replace img element with new element. This is the actual injection.
278 parentNode.replaceChild(injectElem, imgElem);
279 // Mark img element as injected
280 imgElem[__SVGINJECT] = INJECTED;
281 removeOnLoadAttribute(imgElem);
282 // Invoke afterInject hook if set
283 var afterInject = options.afterInject;
284 if (afterInject) {
285 afterInject(imgElem, injectElem);
286 }
287 }
288 } else {
289 svgInvalid(imgElem, options);
290 }
291 }
292
293
294 // Merges any number of options objects into a new object
295 function mergeOptions() {
296 var mergedOptions = {};
297 var args = arguments;
298 // Iterate over all specified options objects and add all properties to the new options object
299 for (var i = 0; i < args[_LENGTH_]; i++) {
300 var argument = args[i];
301 for (var key in argument) {
302 if (argument.hasOwnProperty(key)) {
303 mergedOptions[key] = argument[key];
304 }
305 }
306 }
307 return mergedOptions;
308 }
309
310
311 // Adds the specified CSS to the document's <head> element
312 function addStyleToHead(css) {
313 var head = document[_GET_ELEMENTS_BY_TAG_NAME_]('head')[0];
314 if (head) {
315 var style = document[_CREATE_ELEMENT_](_STYLE_);
316 style.type = 'text/css';
317 style.appendChild(document.createTextNode(css));
318 head.appendChild(style);
319 }
320 }
321
322
323 // Builds an SVG element from the specified SVG string
324 function buildSvgElement(svgStr, verify) {
325 if (verify) {
326 var svgDoc;
327 try {
328 // Parse the SVG string with DOMParser
329 svgDoc = svgStringToSvgDoc(svgStr);
330 } catch(e) {
331 return NULL;
332 }
333 if (svgDoc[_GET_ELEMENTS_BY_TAG_NAME_]('parsererror')[_LENGTH_]) {
334 // DOMParser does not throw an exception, but instead puts parsererror tags in the document
335 return NULL;
336 }
337 return svgDoc.documentElement;
338 } else {
339 var div = document.createElement('div');
340 div.innerHTML = svgStr;
341 return div.firstElementChild;
342 }
343 }
344
345
346 function removeOnLoadAttribute(imgElem) {
347 // Remove the onload attribute. Should only be used to remove the unstyled image flash protection and
348 // make the element visible, not for removing the event listener.
349 imgElem.removeAttribute('onload');
350 }
351
352
353 function errorMessage(msg) {
354 console.error('SVGInject: ' + msg);
355 }
356
357
358 function fail(imgElem, status, options) {
359 imgElem[__SVGINJECT] = FAIL;
360 if (options.onFail) {
361 options.onFail(imgElem, status);
362 } else {
363 errorMessage(status);
364 }
365 }
366
367
368 function svgInvalid(imgElem, options) {
369 removeOnLoadAttribute(imgElem);
370 fail(imgElem, SVG_INVALID, options);
371 }
372
373
374 function svgNotSupported(imgElem, options) {
375 removeOnLoadAttribute(imgElem);
376 fail(imgElem, SVG_NOT_SUPPORTED, options);
377 }
378
379
380 function loadFail(imgElem, options) {
381 fail(imgElem, LOAD_FAIL, options);
382 }
383
384
385 function removeEventListeners(imgElem) {
386 imgElem.onload = NULL;
387 imgElem.onerror = NULL;
388 }
389
390
391 function imgNotSet(msg) {
392 errorMessage('no img element');
393 }
394
395
396 function createSVGInject(globalName, options) {
397 var defaultOptions = mergeOptions(DEFAULT_OPTIONS, options);
398 var svgLoadCache = {};
399
400 if (IS_SVG_SUPPORTED) {
401 // If the browser supports SVG, add a small stylesheet that hides the <img> elements until
402 // injection is finished. This avoids showing the unstyled SVGs before style is applied.
403 addStyleToHead('img[onload^="' + globalName + '("]{visibility:hidden;}');
404 }
405
406
407 /**
408 * SVGInject
409 *
410 * Injects the SVG specified in the `src` attribute of the specified `img` element or array of `img`
411 * elements. Returns a Promise object which resolves if all passed in `img` elements have either been
412 * injected or failed to inject (Only if a global Promise object is available like in all modern browsers
413 * or through a polyfill).
414 *
415 * Options:
416 * useCache: If set to `true` the SVG will be cached using the absolute URL. Default value is `true`.
417 * copyAttributes: If set to `true` the attributes will be copied from `img` to `svg`. Dfault value
418 * is `true`.
419 * makeIdsUnique: If set to `true` the ID of elements in the `<defs>` element that can be references by
420 * property values (for example 'clipPath') are made unique by appending "--inject-X", where X is a
421 * running number which increases with each injection. This is done to avoid duplicate IDs in the DOM.
422 * beforeLoad: Hook before SVG is loaded. The `img` element is passed as a parameter. If the hook returns
423 * a string it is used as the URL instead of the `img` element's `src` attribute.
424 * afterLoad: Hook after SVG is loaded. The loaded `svg` element and `svg` string are passed as a
425 * parameters. If caching is active this hook will only get called once for injected SVGs with the
426 * same absolute path. Changes to the `svg` element in this hook will be applied to all injected SVGs
427 * with the same absolute path. It's also possible to return an `svg` string or `svg` element which
428 * will then be used for the injection.
429 * beforeInject: Hook before SVG is injected. The `img` and `svg` elements are passed as parameters. If
430 * any html element is returned it gets injected instead of applying the default SVG injection.
431 * afterInject: Hook after SVG is injected. The `img` and `svg` elements are passed as parameters.
432 * onAllFinish: Hook after all `img` elements passed to an SVGInject() call have either been injected or
433 * failed to inject.
434 * onFail: Hook after injection fails. The `img` element and a `status` string are passed as an parameter.
435 * The `status` can be either `'SVG_NOT_SUPPORTED'` (the browser does not support SVG),
436 * `'SVG_INVALID'` (the SVG is not in a valid format) or `'LOAD_FAILED'` (loading of the SVG failed).
437 *
438 * @param {HTMLImageElement} img - an img element or an array of img elements
439 * @param {Object} [options] - optional parameter with [options](#options) for this injection.
440 */
441 function SVGInject(img, options) {
442 options = mergeOptions(defaultOptions, options);
443
444 var run = function(resolve) {
445 var allFinish = function() {
446 var onAllFinish = options.onAllFinish;
447 if (onAllFinish) {
448 onAllFinish();
449 }
450 resolve && resolve();
451 };
452
453 if (img && typeof img[_LENGTH_] != _UNDEFINED_) {
454 // an array like structure of img elements
455 var injectIndex = 0;
456 var injectCount = img[_LENGTH_];
457
458 if (injectCount == 0) {
459 allFinish();
460 } else {
461 var finish = function() {
462 if (++injectIndex == injectCount) {
463 allFinish();
464 }
465 };
466
467 for (var i = 0; i < injectCount; i++) {
468 SVGInjectElement(img[i], options, finish);
469 }
470 }
471 } else {
472 // only one img element
473 SVGInjectElement(img, options, allFinish);
474 }
475 };
476
477 // return a Promise object if globally available
478 return typeof Promise == _UNDEFINED_ ? run() : new Promise(run);
479 }
480
481
482 // Injects a single svg element. Options must be already merged with the default options.
483 function SVGInjectElement(imgElem, options, callback) {
484 if (imgElem) {
485 var svgInjectAttributeValue = imgElem[__SVGINJECT];
486 if (!svgInjectAttributeValue) {
487 removeEventListeners(imgElem);
488
489 if (!IS_SVG_SUPPORTED) {
490 svgNotSupported(imgElem, options);
491 callback();
492 return;
493 }
494 // Invoke beforeLoad hook if set. If the beforeLoad returns a value use it as the src for the load
495 // URL path. Else use the imgElem's src attribute value.
496 var beforeLoad = options.beforeLoad;
497 var src = (beforeLoad && beforeLoad(imgElem)) || imgElem[_GET_ATTRIBUTE_]('src');
498
499 if (!src) {
500 // If no image src attribute is set do no injection. This can only be reached by using javascript
501 // because if no src attribute is set the onload and onerror events do not get called
502 if (src === '') {
503 loadFail(imgElem, options);
504 }
505 callback();
506 return;
507 }
508
509 // set array so later calls can register callbacks
510 var onFinishCallbacks = [];
511 imgElem[__SVGINJECT] = onFinishCallbacks;
512
513 var onFinish = function() {
514 callback();
515 onFinishCallbacks.forEach(function(onFinishCallback) {
516 onFinishCallback();
517 });
518 };
519
520 var absUrl = getAbsoluteUrl(src);
521 var useCacheOption = options.useCache;
522 var makeIdsUniqueOption = options.makeIdsUnique;
523
524 var setSvgLoadCacheValue = function(val) {
525 if (useCacheOption) {
526 svgLoadCache[absUrl].forEach(function(svgLoad) {
527 svgLoad(val);
528 });
529 svgLoadCache[absUrl] = val;
530 }
531 };
532
533 if (useCacheOption) {
534 var svgLoad = svgLoadCache[absUrl];
535
536 var handleLoadValue = function(loadValue) {
537 if (loadValue === LOAD_FAIL) {
538 loadFail(imgElem, options);
539 } else if (loadValue === SVG_INVALID) {
540 svgInvalid(imgElem, options);
541 } else {
542 var hasUniqueIds = loadValue[0];
543 var svgString = loadValue[1];
544 var uniqueIdsSvgString = loadValue[2];
545 var svgElem;
546
547 if (makeIdsUniqueOption) {
548 if (hasUniqueIds === NULL) {
549 // IDs for the SVG string have not been made unique before. This may happen if previous
550 // injection of a cached SVG have been run with the option makedIdsUnique set to false
551 svgElem = buildSvgElement(svgString, false);
552 hasUniqueIds = makeIdsUnique(svgElem, false);
553
554 loadValue[0] = hasUniqueIds;
555 loadValue[2] = hasUniqueIds && svgElemToSvgString(svgElem);
556 } else if (hasUniqueIds) {
557 // Make IDs unique for already cached SVGs with better performance
558 svgString = makeIdsUniqueCached(uniqueIdsSvgString);
559 }
560 }
561
562 svgElem = svgElem || buildSvgElement(svgString, false);
563
564 inject(imgElem, svgElem, absUrl, options);
565 }
566 onFinish();
567 };
568
569 if (typeof svgLoad != _UNDEFINED_) {
570 // Value for url exists in cache
571 if (svgLoad.isCallbackQueue) {
572 // Same url has been cached, but value has not been loaded yet, so add to callbacks
573 svgLoad.push(handleLoadValue);
574 } else {
575 handleLoadValue(svgLoad);
576 }
577 return;
578 } else {
579 var svgLoad = [];
580 // set property isCallbackQueue to Array to differentiate from array with cached loaded values
581 svgLoad.isCallbackQueue = true;
582 svgLoadCache[absUrl] = svgLoad;
583 }
584 }
585
586 // Load the SVG because it is not cached or caching is disabled
587 loadSvg(absUrl, function(svgXml, svgString) {
588 // Use the XML from the XHR request if it is an instance of Document. Otherwise
589 // (for example of IE9), create the svg document from the svg string.
590 var svgElem = svgXml instanceof Document ? svgXml.documentElement : buildSvgElement(svgString, true);
591
592 var afterLoad = options.afterLoad;
593 if (afterLoad) {
594 // Invoke afterLoad hook which may modify the SVG element. After load may also return a new
595 // svg element or svg string
596 var svgElemOrSvgString = afterLoad(svgElem, svgString) || svgElem;
597 if (svgElemOrSvgString) {
598 // Update svgElem and svgString because of modifications to the SVG element or SVG string in
599 // the afterLoad hook, so the modified SVG is also used for all later cached injections
600 var isString = typeof svgElemOrSvgString == 'string';
601 svgString = isString ? svgElemOrSvgString : svgElemToSvgString(svgElem);
602 svgElem = isString ? buildSvgElement(svgElemOrSvgString, true) : svgElemOrSvgString;
603 }
604 }
605
606 if (svgElem instanceof SVGElement) {
607 var hasUniqueIds = NULL;
608 if (makeIdsUniqueOption) {
609 hasUniqueIds = makeIdsUnique(svgElem, false);
610 }
611
612 if (useCacheOption) {
613 var uniqueIdsSvgString = hasUniqueIds && svgElemToSvgString(svgElem);
614 // set an array with three entries to the load cache
615 setSvgLoadCacheValue([hasUniqueIds, svgString, uniqueIdsSvgString]);
616 }
617
618 inject(imgElem, svgElem, absUrl, options);
619 } else {
620 svgInvalid(imgElem, options);
621 setSvgLoadCacheValue(SVG_INVALID);
622 }
623 onFinish();
624 }, function() {
625 loadFail(imgElem, options);
626 setSvgLoadCacheValue(LOAD_FAIL);
627 onFinish();
628 });
629 } else {
630 if (Array.isArray(svgInjectAttributeValue)) {
631 // svgInjectAttributeValue is an array. Injection is not complete so register callback
632 svgInjectAttributeValue.push(callback);
633 } else {
634 callback();
635 }
636 }
637 } else {
638 imgNotSet();
639 }
640 }
641
642
643 /**
644 * Sets the default [options](#options) for SVGInject.
645 *
646 * @param {Object} [options] - default [options](#options) for an injection.
647 */
648 SVGInject.setOptions = function(options) {
649 defaultOptions = mergeOptions(defaultOptions, options);
650 };
651
652
653 // Create a new instance of SVGInject
654 SVGInject.create = createSVGInject;
655
656
657 /**
658 * Used in onerror Event of an `<img>` element to handle cases when the loading the original src fails
659 * (for example if file is not found or if the browser does not support SVG). This triggers a call to the
660 * options onFail hook if available. The optional second parameter will be set as the new src attribute
661 * for the img element.
662 *
663 * @param {HTMLImageElement} img - an img element
664 * @param {String} [fallbackSrc] - optional parameter fallback src
665 */
666 SVGInject.err = function(img, fallbackSrc) {
667 if (img) {
668 if (img[__SVGINJECT] != FAIL) {
669 removeEventListeners(img);
670
671 if (!IS_SVG_SUPPORTED) {
672 svgNotSupported(img, defaultOptions);
673 } else {
674 removeOnLoadAttribute(img);
675 loadFail(img, defaultOptions);
676 }
677 if (fallbackSrc) {
678 removeOnLoadAttribute(img);
679 img.src = fallbackSrc;
680 }
681 }
682 } else {
683 imgNotSet();
684 }
685 };
686
687 window[globalName] = SVGInject;
688
689 return SVGInject;
690 }
691
692 var SVGInjectInstance = createSVGInject('SVGInject');
693
694 if (typeof module == 'object' && typeof module.exports == 'object') {
695 module.exports = SVGInjectInstance;
696 }
697})(window, document);
697 \ No newline at end of file \ No newline at end of file
public/script.js+2 -1
@@ -5,6 +5,7 @@ import {
5 localforage,5 localforage,
6 Handlebars,6 Handlebars,
7 DiffMatchPatch,7 DiffMatchPatch,
8 SVGInject,
8 initLibraryShims,9 initLibraryShims,
9 default as libs,10 default as libs,
10} from './lib.js';11} from './lib.js';
@@ -2136,7 +2137,7 @@ function insertSVGIcon(mes, extra) {
2136 mes.find('.timestamp').after(image);2137 mes.find('.timestamp').after(image);
2137 }2138 }
21382139
2139 await SVGInject(this);2140 await SVGInject(image);
2140 };2141 };
2141}2142}
21422143