1 | #!/usr/bin/env node
|
2 | (function() {
|
3 | ;
|
4 | var ASCIIDrawing, ASCIIMapping, CSVDrawing, CoffeeMapping, Context, DOMParser, DSVDrawing, Drawing, Drawings, DynamicSymbol, Input, JSMapping, Mapping, Mappings, SSVDrawing, SVGNS, SVGTilerException, StaticSymbol, Symbol, TSVDrawing, XLINKNS, XLSXDrawings, XMLSerializer, allBlank, attributeOrStyle, blankCells, bufferSize, convertSVG, domImplementation, escapeId, exports, extensionMap, extensionOf, fs, graphemeSplitter, help, isAuto, main, overflowBox, parseNum, path, postprocess, prettyXML, sanitize, splitIntoLines, svgBBox, svgtiler, unrecognizedSymbol, whitespace, xmldom, zIndex, zeroSizeReplacement,
|
5 | indexOf = [].indexOf,
|
6 | hasProp = {}.hasOwnProperty;
|
7 |
|
8 | if (typeof window === "undefined" || window === null) {
|
9 | path = require('path');
|
10 | fs = require('fs');
|
11 | xmldom = require('xmldom');
|
12 | DOMParser = xmldom.DOMParser;
|
13 | domImplementation = new xmldom.DOMImplementation();
|
14 | XMLSerializer = xmldom.XMLSerializer;
|
15 | prettyXML = require('prettify-xml');
|
16 | graphemeSplitter = new require('grapheme-splitter')();
|
17 | svgtiler = require('../package.json');
|
18 | require('coffeescript/register');
|
19 | } else {
|
20 | DOMParser = window.DOMParser;
|
21 | domImplementation = document.implementation;
|
22 | path = {
|
23 | extname: function(x) {
|
24 | return /\.[^\/]+$/.exec(x)[0];
|
25 | },
|
26 | dirname: function(x) {
|
27 | return /[^]*\/|/.exec(x)[0];
|
28 | }
|
29 | };
|
30 | }
|
31 |
|
32 | SVGNS = 'http://www.w3.org/2000/svg';
|
33 |
|
34 | XLINKNS = 'http://www.w3.org/1999/xlink';
|
35 |
|
36 | splitIntoLines = function(data) {
|
37 | return data.replace('\r\n', '\n').replace('\r', '\n').split('\n');
|
38 | };
|
39 |
|
40 | whitespace = /[\s\uFEFF\xA0]+/;
|
41 |
|
42 | extensionOf = function(filename) {
|
43 | return path.extname(filename).toLowerCase();
|
44 | };
|
45 |
|
46 | SVGTilerException = class SVGTilerException {
|
47 | constructor(message) {
|
48 | this.message = message;
|
49 | }
|
50 |
|
51 | toString() {
|
52 | return `svgtiler: ${this.message}`;
|
53 | }
|
54 |
|
55 | };
|
56 |
|
57 | overflowBox = function(xml) {
|
58 | if (xml.documentElement.hasAttribute('overflowBox')) {
|
59 | return xml.documentElement.getAttribute('overflowBox').split(/\s*,?\s+/).map(parseFloat);
|
60 | } else {
|
61 | return null;
|
62 | }
|
63 | };
|
64 |
|
65 | parseNum = function(x) {
|
66 | var parsed;
|
67 | parsed = parseFloat(x);
|
68 | if (isNaN(parsed)) {
|
69 | return null;
|
70 | } else {
|
71 | return parsed;
|
72 | }
|
73 | };
|
74 |
|
75 | svgBBox = function(xml) {
|
76 | var recurse, viewBox;
|
77 |
|
78 |
|
79 |
|
80 |
|
81 |
|
82 |
|
83 | if (xml.documentElement.hasAttribute('viewBox')) {
|
84 | viewBox = xml.documentElement.getAttribute('viewBox').split(/\s*,?\s+/).map(parseNum);
|
85 | if (indexOf.call(viewBox, null) >= 0) {
|
86 | return null;
|
87 | } else {
|
88 | return viewBox;
|
89 | }
|
90 | } else {
|
91 | recurse = function(node) {
|
92 | var child, coord, cx, cy, point, points, r, ref, ref1, ref10, ref11, ref12, ref13, ref14, ref15, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, rx, ry, viewBoxes, x1, x2, xmax, xmin, xs, y1, y2, ymax, ymin, ys;
|
93 | if (node.nodeType !== node.ELEMENT_NODE || ((ref = node.tagName) === 'defs' || ref === 'symbol' || ref === 'use')) {
|
94 | return null;
|
95 | }
|
96 | switch (node.tagName) {
|
97 | case 'rect':
|
98 | case 'image':
|
99 |
|
100 | return [(ref1 = parseNum(node.getAttribute('x'))) != null ? ref1 : 0, (ref2 = parseNum(node.getAttribute('y'))) != null ? ref2 : 0, (ref3 = parseNum(node.getAttribute('width'))) != null ? ref3 : 0, (ref4 = parseNum(node.getAttribute('height'))) != null ? ref4 : 0];
|
101 | case 'circle':
|
102 | cx = (ref5 = parseNum(node.getAttribute('cx'))) != null ? ref5 : 0;
|
103 | cy = (ref6 = parseNum(node.getAttribute('cy'))) != null ? ref6 : 0;
|
104 | r = (ref7 = parseNum(node.getAttribute('r'))) != null ? ref7 : 0;
|
105 | return [cx - r, cy - r, 2 * r, 2 * r];
|
106 | case 'ellipse':
|
107 | cx = (ref8 = parseNum(node.getAttribute('cx'))) != null ? ref8 : 0;
|
108 | cy = (ref9 = parseNum(node.getAttribute('cy'))) != null ? ref9 : 0;
|
109 | rx = (ref10 = parseNum(node.getAttribute('rx'))) != null ? ref10 : 0;
|
110 | ry = (ref11 = parseNum(node.getAttribute('ry'))) != null ? ref11 : 0;
|
111 | return [cx - rx, cy - ry, 2 * rx, 2 * ry];
|
112 | case 'line':
|
113 | x1 = (ref12 = parseNum(node.getAttribute('x1'))) != null ? ref12 : 0;
|
114 | y1 = (ref13 = parseNum(node.getAttribute('y1'))) != null ? ref13 : 0;
|
115 | x2 = (ref14 = parseNum(node.getAttribute('x2'))) != null ? ref14 : 0;
|
116 | y2 = (ref15 = parseNum(node.getAttribute('y2'))) != null ? ref15 : 0;
|
117 | xmin = Math.min(x1, x2);
|
118 | ymin = Math.min(y1, y2);
|
119 | return [xmin, ymin, Math.max(x1, x2) - xmin, Math.max(y1, y2) - ymin];
|
120 | case 'polyline':
|
121 | case 'polygon':
|
122 | points = (function() {
|
123 | var k, len, ref16, results;
|
124 | ref16 = node.getAttribute('points').trim().split(/\s+/);
|
125 | results = [];
|
126 | for (k = 0, len = ref16.length; k < len; k++) {
|
127 | point = ref16[k];
|
128 | results.push((function() {
|
129 | var l, len1, ref17, results1;
|
130 | ref17 = point.split(/,/);
|
131 | results1 = [];
|
132 | for (l = 0, len1 = ref17.length; l < len1; l++) {
|
133 | coord = ref17[l];
|
134 | results1.push(parseFloat(coord));
|
135 | }
|
136 | return results1;
|
137 | })());
|
138 | }
|
139 | return results;
|
140 | })();
|
141 | xs = (function() {
|
142 | var k, len, results;
|
143 | results = [];
|
144 | for (k = 0, len = points.length; k < len; k++) {
|
145 | point = points[k];
|
146 | results.push(point[0]);
|
147 | }
|
148 | return results;
|
149 | })();
|
150 | ys = (function() {
|
151 | var k, len, results;
|
152 | results = [];
|
153 | for (k = 0, len = points.length; k < len; k++) {
|
154 | point = points[k];
|
155 | results.push(point[1]);
|
156 | }
|
157 | return results;
|
158 | })();
|
159 | xmin = Math.min(...xs);
|
160 | ymin = Math.min(...ys);
|
161 | if (isNaN(xmin) || isNaN(ymin)) {
|
162 | return null;
|
163 | } else {
|
164 | return [xmin, ymin, Math.max(...xs) - xmin, Math.max(...ys) - ymin];
|
165 | }
|
166 | break;
|
167 | default:
|
168 | viewBoxes = (function() {
|
169 | var k, len, ref16, results;
|
170 | ref16 = node.childNodes;
|
171 | results = [];
|
172 | for (k = 0, len = ref16.length; k < len; k++) {
|
173 | child = ref16[k];
|
174 | results.push(recurse(child));
|
175 | }
|
176 | return results;
|
177 | })();
|
178 | viewBoxes = (function() {
|
179 | var k, len, results;
|
180 | results = [];
|
181 | for (k = 0, len = viewBoxes.length; k < len; k++) {
|
182 | viewBox = viewBoxes[k];
|
183 | if (viewBox != null) {
|
184 | results.push(viewBox);
|
185 | }
|
186 | }
|
187 | return results;
|
188 | })();
|
189 | xmin = Math.min(...((function() {
|
190 | var k, len, results;
|
191 | results = [];
|
192 | for (k = 0, len = viewBoxes.length; k < len; k++) {
|
193 | viewBox = viewBoxes[k];
|
194 | results.push(viewBox[0]);
|
195 | }
|
196 | return results;
|
197 | })()));
|
198 | ymin = Math.min(...((function() {
|
199 | var k, len, results;
|
200 | results = [];
|
201 | for (k = 0, len = viewBoxes.length; k < len; k++) {
|
202 | viewBox = viewBoxes[k];
|
203 | results.push(viewBox[1]);
|
204 | }
|
205 | return results;
|
206 | })()));
|
207 | xmax = Math.max(...((function() {
|
208 | var k, len, results;
|
209 | results = [];
|
210 | for (k = 0, len = viewBoxes.length; k < len; k++) {
|
211 | viewBox = viewBoxes[k];
|
212 | results.push(viewBox[0] + viewBox[2]);
|
213 | }
|
214 | return results;
|
215 | })()));
|
216 | ymax = Math.max(...((function() {
|
217 | var k, len, results;
|
218 | results = [];
|
219 | for (k = 0, len = viewBoxes.length; k < len; k++) {
|
220 | viewBox = viewBoxes[k];
|
221 | results.push(viewBox[1] + viewBox[3]);
|
222 | }
|
223 | return results;
|
224 | })()));
|
225 | return [xmin, ymin, xmax - xmin, ymax - ymin];
|
226 | }
|
227 | };
|
228 | viewBox = recurse(xml.documentElement);
|
229 | if (indexOf.call(viewBox, 2e308) >= 0 || indexOf.call(viewBox, -2e308) >= 0) {
|
230 | return null;
|
231 | } else {
|
232 | return viewBox;
|
233 | }
|
234 | }
|
235 | };
|
236 |
|
237 | isAuto = function(xml, prop) {
|
238 | return xml.documentElement.hasAttribute(prop) && /^\s*auto\s*$/i.test(xml.documentElement.getAttribute(prop));
|
239 | };
|
240 |
|
241 | attributeOrStyle = function(node, attr, styleKey = attr) {
|
242 | var match, style, value;
|
243 | if (value = node.getAttribute(attr)) {
|
244 | return value.trim();
|
245 | } else {
|
246 | style = node.getAttribute('style');
|
247 | if (style) {
|
248 | match = /(?:^|;)\s*#{styleKey}\s*:\s*([^;\s][^;]*)/i.exec(style);
|
249 | return match != null ? match[1] : void 0;
|
250 | }
|
251 | }
|
252 | };
|
253 |
|
254 | zIndex = function(node) {
|
255 | var z;
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 | z = parseInt(attributeOrStyle(node, 'z-index'));
|
262 | if (isNaN(z)) {
|
263 | return 0;
|
264 | } else {
|
265 | return z;
|
266 | }
|
267 | };
|
268 |
|
269 | Symbol = (function() {
|
270 | class Symbol {
|
271 | static parse(key, data, dirname) {
|
272 | var extension, filename, size;
|
273 | if (data == null) {
|
274 | throw new SVGTilerException(`Attempt to create symbol '${key}' without data`);
|
275 | } else if (typeof data === 'function') {
|
276 | return new DynamicSymbol(key, data, dirname);
|
277 | } else if (data.function != null) {
|
278 | return new DynamicSymbol(key, data.function, dirname);
|
279 | } else {
|
280 |
|
281 |
|
282 |
|
283 | if (typeof data === 'object' && (data.type != null) && (data.props != null)) {
|
284 | data = require('preact-render-to-string')(data);
|
285 | }
|
286 | return new StaticSymbol(key, (function() {
|
287 | if (typeof data === 'string') {
|
288 | if (data.trim() === '') {
|
289 | return {
|
290 | svg: '<symbol viewBox="0 0 0 0"/>'
|
291 | };
|
292 | } else if (data.indexOf('<') < 0) {
|
293 | if (dirname != null) {
|
294 | filename = path.join(dirname, data);
|
295 | } else {
|
296 | filename = data;
|
297 | }
|
298 | extension = extensionOf(data);
|
299 |
|
300 |
|
301 |
|
302 | switch (extension) {
|
303 | case '.png':
|
304 | case '.jpg':
|
305 | case '.jpeg':
|
306 | case '.gif':
|
307 | size = require('image-size')(filename);
|
308 | return {
|
309 | svg: `<image xlink:href="${encodeURI(data)}" width="${size.width}" height="${size.height}"${this.imageRendering}/>`
|
310 | };
|
311 | case '.svg':
|
312 | return {
|
313 | filename: filename,
|
314 | svg: fs.readFileSync(filename, {
|
315 | encoding: this.svgEncoding
|
316 | })
|
317 | };
|
318 | default:
|
319 | throw new SVGTilerException(`Unrecognized extension in filename '${data}' for symbol '${key}'`);
|
320 | }
|
321 | } else {
|
322 | return {
|
323 | svg: data
|
324 | };
|
325 | }
|
326 | } else {
|
327 | return data;
|
328 | }
|
329 | }).call(this));
|
330 | }
|
331 | }
|
332 |
|
333 | includes(substring) {
|
334 | return this.key.indexOf(substring) >= 0;
|
335 | }
|
336 |
|
337 | };
|
338 |
|
339 | Symbol.svgEncoding = 'utf8';
|
340 |
|
341 | Symbol.forceWidth = null;
|
342 |
|
343 | Symbol.forceHeight = null;
|
344 |
|
345 | Symbol.texText = false;
|
346 |
|
347 | |
348 |
|
349 |
|
350 |
|
351 |
|
352 |
|
353 | Symbol.imageRendering = ' image-rendering="optimizeSpeed" style="image-rendering:pixelated"';
|
354 |
|
355 | return Symbol;
|
356 |
|
357 | }).call(this);
|
358 |
|
359 |
|
360 | escapeId = function(key) {
|
361 | |
362 |
|
363 |
|
364 |
|
365 |
|
366 |
|
367 |
|
368 |
|
369 |
|
370 |
|
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 |
|
377 |
|
378 |
|
379 |
|
380 |
|
381 |
|
382 |
|
383 |
|
384 |
|
385 | return (encodeURIComponent(key).replace(/%/g, '$')) || '$BLANK$';
|
386 | };
|
387 |
|
388 | zeroSizeReplacement = 1;
|
389 |
|
390 | StaticSymbol = (function() {
|
391 | class StaticSymbol extends Symbol {
|
392 | constructor(key1, options) {
|
393 | var extract, key, overflow, value, warnings;
|
394 | super();
|
395 | this.key = key1;
|
396 | for (key in options) {
|
397 | if (!hasProp.call(options, key)) continue;
|
398 | value = options[key];
|
399 | this[key] = value;
|
400 | }
|
401 |
|
402 |
|
403 |
|
404 | this.svg = this.svg.replace(/^\s*<(?:[^<>'"\/]|'[^']*'|"[^"]*")*\s*(\/?\s*>)/, function(match, end) {
|
405 | if (indexOf.call(match, 'xmlns') < 0) {
|
406 | match = match.slice(0, match.length - end.length) + ` xmlns='${SVGNS}'` + match.slice(match.length - end.length);
|
407 | }
|
408 | return match;
|
409 | });
|
410 | this.xml = new DOMParser({
|
411 | locator: {
|
412 | line: 1,
|
413 | col: 1
|
414 | },
|
415 | errorHandler: (level, msg, indent = ' ') => {
|
416 | msg = msg.replace(/^\[xmldom [^\[\]]*\]\t/, '');
|
417 | msg = msg.replace(/@#\[line:(\d+),col:(\d+)\]$/, (match, line, col) => {
|
418 | var lines;
|
419 | lines = this.svg.split('\n');
|
420 | return (line > 1 ? indent + lines[line - 2] + '\n' : '') + indent + lines[line - 1] + '\n' + indent + ' '.repeat(col - 1) + '^^^' + (line < lines.length ? '\n' + indent + lines[line] : '');
|
421 | });
|
422 | return console.error(`SVG parse \${level} in symbol '${this.key}': ${msg}`);
|
423 | }
|
424 | }).parseFromString(this.svg, 'image/svg+xml');
|
425 |
|
426 |
|
427 | this.xml.documentElement.removeAttribute('xmlns');
|
428 | this.viewBox = svgBBox(this.xml);
|
429 | this.overflowBox = overflowBox(this.xml);
|
430 | overflow = attributeOrStyle(this.xml.documentElement, 'overflow');
|
431 | this.overflowVisible = (overflow != null) && /^visible\b/.test(overflow);
|
432 | this.width = this.height = null;
|
433 | if (this.viewBox != null) {
|
434 | this.width = this.viewBox[2];
|
435 | this.height = this.viewBox[3];
|
436 | |
437 |
|
438 |
|
439 |
|
440 |
|
441 | if (this.overflowVisible) {
|
442 | if (this.width === 0) {
|
443 | this.viewBox[2] = zeroSizeReplacement;
|
444 | }
|
445 | if (this.height === 0) {
|
446 | this.viewBox[3] = zeroSizeReplacement;
|
447 | }
|
448 | }
|
449 | }
|
450 | if (Symbol.forceWidth != null) {
|
451 | this.width = Symbol.forceWidth;
|
452 | }
|
453 | if (Symbol.forceHeight != null) {
|
454 | this.height = Symbol.forceHeight;
|
455 | }
|
456 | warnings = [];
|
457 | if (this.width == null) {
|
458 | warnings.push('width');
|
459 | this.width = 0;
|
460 | }
|
461 | if (this.height == null) {
|
462 | warnings.push('height');
|
463 | this.height = 0;
|
464 | }
|
465 | if (warnings.length > 0) {
|
466 | console.warn(`Failed to detect ${warnings.join(' and ')} of SVG for symbol '${this.key}'`);
|
467 | }
|
468 |
|
469 |
|
470 | this.autoWidth = isAuto(this.xml, 'width');
|
471 | this.autoHeight = isAuto(this.xml, 'height');
|
472 | if (this.autoWidth) {
|
473 | this.xml.documentElement.removeAttribute('width');
|
474 | }
|
475 | if (this.autoHeight) {
|
476 | this.xml.documentElement.removeAttribute('height');
|
477 | }
|
478 | this.zIndex = zIndex(this.xml.documentElement);
|
479 |
|
480 | if (Symbol.texText) {
|
481 | this.text = [];
|
482 | extract = (node) => {
|
483 | var child, nextChild, results;
|
484 | if (!node.hasChildNodes()) {
|
485 | return;
|
486 | }
|
487 | child = node.lastChild;
|
488 | results = [];
|
489 | while (child != null) {
|
490 | nextChild = child.previousSibling;
|
491 | if (child.nodeName === 'text') {
|
492 | this.text.push(child);
|
493 | node.removeChild(child);
|
494 | } else {
|
495 | extract(child);
|
496 | }
|
497 | results.push(child = nextChild);
|
498 | }
|
499 | return results;
|
500 | };
|
501 | extract(this.xml.documentElement);
|
502 | }
|
503 | }
|
504 |
|
505 | id() {
|
506 | return escapeId(this.key);
|
507 | }
|
508 |
|
509 | use() {
|
510 | return this;
|
511 | }
|
512 |
|
513 | };
|
514 |
|
515 | StaticSymbol.prototype.usesContext = false;
|
516 |
|
517 | return StaticSymbol;
|
518 |
|
519 | }).call(this);
|
520 |
|
521 | DynamicSymbol = (function() {
|
522 | class DynamicSymbol extends Symbol {
|
523 | constructor(key1, func, dirname1) {
|
524 | super();
|
525 | this.key = key1;
|
526 | this.func = func;
|
527 | this.dirname = dirname1;
|
528 | this.versions = {};
|
529 | this.nversions = 0;
|
530 | this.constructor.all.push(this);
|
531 | }
|
532 |
|
533 | static resetAll() {
|
534 | var k, len, ref, results, symbol;
|
535 | ref = this.all;
|
536 |
|
537 |
|
538 | results = [];
|
539 | for (k = 0, len = ref.length; k < len; k++) {
|
540 | symbol = ref[k];
|
541 | symbol.versions = {};
|
542 | results.push(symbol.nversions = 0);
|
543 | }
|
544 | return results;
|
545 | }
|
546 |
|
547 | use(context) {
|
548 | var result, string, version;
|
549 | result = this.func.call(context);
|
550 | if (result == null) {
|
551 | throw new Error(`Function for symbol ${this.key} returned ${result}`);
|
552 | }
|
553 |
|
554 |
|
555 |
|
556 | string = JSON.stringify(result);
|
557 | if (!(string in this.versions)) {
|
558 | version = this.nversions++;
|
559 | this.versions[string] = Symbol.parse(`${this.key}$v${version}`, result, this.dirname);
|
560 | this.versions[string].id = () => {
|
561 | return `${escapeId(this.key)}$v${version}`;
|
562 | };
|
563 | }
|
564 | return this.versions[string];
|
565 | }
|
566 |
|
567 | };
|
568 |
|
569 | DynamicSymbol.all = [];
|
570 |
|
571 | DynamicSymbol.prototype.usesContext = true;
|
572 |
|
573 | return DynamicSymbol;
|
574 |
|
575 | }).call(this);
|
576 |
|
577 |
|
578 |
|
579 |
|
580 | unrecognizedSymbol = new StaticSymbol('$UNRECOGNIZED$', {
|
581 | svg: `<symbol viewBox="0 0 200 200" preserveAspectRatio="none" width="auto" height="auto">
|
582 | <rect width="200" height="200" fill="yellow"/>
|
583 | <path xmlns="http://www.w3.org/2000/svg" stroke="none" fill="red" d="M 200,100 100,200 0,100 100,0 200,100 z M 135.64709,74.70585 q 0,-13.52935 -10.00006,-22.52943 -9.99999,-8.99999 -24.35289,-8.99999 -17.29415,0 -30.117661,5.29409 L 69.05879,69.52938 q 9.764731,-6.23528 21.52944,-6.23528 8.82356,0 14.58824,4.82351 5.76469,4.82351 5.76469,12.70589 0,8.5883 -9.94117,21.70588 -9.94117,13.11766 -9.94117,26.76473 l 17.88236,0 q 0,-6.3529 6.9412,-14.9412 11.76471,-14.58816 12.82351,-16.35289 6.9412,-11.05887 6.9412,-23.29417 z m -22.00003,92.11771 0,-24.70585 -27.29412,0 0,24.70585 27.29412,0 z"/>
|
584 | </symbol>`
|
585 | });
|
586 |
|
587 | unrecognizedSymbol.id = function() {
|
588 | return '$UNRECOGNIZED$';
|
589 | };
|
590 |
|
591 | Input = (function() {
|
592 | class Input {
|
593 | static parseFile(filename, filedata) {
|
594 | var input;
|
595 |
|
596 | input = new (this)();
|
597 | input.filename = filename;
|
598 | if (filedata == null) {
|
599 | filedata = fs.readFileSync(filename, {
|
600 | encoding: this.encoding
|
601 | });
|
602 | }
|
603 | input.parse(filedata);
|
604 | return input;
|
605 | }
|
606 |
|
607 | static recognize(filename, filedata) {
|
608 | var extension;
|
609 |
|
610 | extension = extensionOf(filename);
|
611 | if (extension in extensionMap) {
|
612 | return extensionMap[extension].parseFile(filename, filedata);
|
613 | } else {
|
614 | throw new SVGTilerException(`Unrecognized extension in filename ${filename}`);
|
615 | }
|
616 | }
|
617 |
|
618 | };
|
619 |
|
620 | Input.encoding = 'utf8';
|
621 |
|
622 | return Input;
|
623 |
|
624 | }).call(this);
|
625 |
|
626 | Mapping = class Mapping extends Input {
|
627 | load(data) {
|
628 | this.map = {};
|
629 | if (typeof data === 'function') {
|
630 | return this.function = data;
|
631 | } else {
|
632 | return this.merge(data);
|
633 | }
|
634 | }
|
635 |
|
636 | merge(data) {
|
637 | var dirname, key, results, value;
|
638 | if (this.filename != null) {
|
639 | dirname = path.dirname(this.filename);
|
640 | }
|
641 | results = [];
|
642 | for (key in data) {
|
643 | if (!hasProp.call(data, key)) continue;
|
644 | value = data[key];
|
645 | if (!(value instanceof Symbol)) {
|
646 | value = Symbol.parse(key, value, dirname);
|
647 | }
|
648 | results.push(this.map[key] = value);
|
649 | }
|
650 | return results;
|
651 | }
|
652 |
|
653 | lookup(key) {
|
654 | var value;
|
655 | key = key.toString();
|
656 | if (key in this.map) {
|
657 | return this.map[key];
|
658 | } else if (this.function != null) {
|
659 |
|
660 |
|
661 |
|
662 | value = this.function(key);
|
663 | if (value != null) {
|
664 | return this.map[key] = Symbol.parse(key, value);
|
665 | } else {
|
666 | return value;
|
667 | }
|
668 | } else {
|
669 | return void 0;
|
670 | }
|
671 | }
|
672 |
|
673 | };
|
674 |
|
675 | ASCIIMapping = (function() {
|
676 | class ASCIIMapping extends Mapping {
|
677 | parse(data) {
|
678 | var k, key, len, line, map, ref, separator;
|
679 | map = {};
|
680 | ref = splitIntoLines(data);
|
681 | for (k = 0, len = ref.length; k < len; k++) {
|
682 | line = ref[k];
|
683 | separator = whitespace.exec(line);
|
684 | if (separator == null) {
|
685 | continue;
|
686 | }
|
687 | if (separator.index === 0) {
|
688 | if (separator[0].length === 1) {
|
689 |
|
690 | key = '';
|
691 | } else {
|
692 |
|
693 | key = line[0];
|
694 | }
|
695 | } else {
|
696 | key = line.slice(0, separator.index);
|
697 | }
|
698 | map[key] = line.slice(separator.index + separator[0].length);
|
699 | }
|
700 | return this.load(map);
|
701 | }
|
702 |
|
703 | };
|
704 |
|
705 | ASCIIMapping.title = "ASCII mapping file";
|
706 |
|
707 | ASCIIMapping.help = "Each line is <symbol-name><space><raw SVG or filename.svg>";
|
708 |
|
709 | return ASCIIMapping;
|
710 |
|
711 | }).call(this);
|
712 |
|
713 | JSMapping = (function() {
|
714 | class JSMapping extends Mapping {
|
715 | parse(data) {
|
716 | var __filename, code;
|
717 | ({code} = require('@babel/core').transform(data, {
|
718 | filename: this.filename,
|
719 | plugins: [
|
720 | [
|
721 | require.resolve('@babel/plugin-transform-react-jsx'),
|
722 | {
|
723 | useBuiltIns: true,
|
724 | pragma: 'preact.h',
|
725 | pragmaFrag: 'preact.Fragment',
|
726 | throwIfNamespace: false
|
727 | }
|
728 | ]
|
729 | ],
|
730 | sourceMaps: 'inline',
|
731 | retainLines: true
|
732 | }));
|
733 | if (0 <= code.indexOf('preact.')) {
|
734 | code = `var preact = require('preact'), h = preact.h; ${code}`;
|
735 | }
|
736 |
|
737 |
|
738 |
|
739 | __filename = path.resolve(this.filename);
|
740 | code = `var __filename = ${JSON.stringify(__filename)}, __dirname = ${JSON.stringify(path.dirname(__filename))}, __require = require; require = (module) => __require(module.startsWith('.') ? __require('path').resolve(__dirname, module) : module); ${code}\n//@ sourceURL=${this.filename}`;
|
741 | return this.load(eval(code));
|
742 | }
|
743 |
|
744 | };
|
745 |
|
746 | JSMapping.title = "JavaScript mapping file";
|
747 |
|
748 | JSMapping.help = "Object mapping symbol names to SYMBOL e.g. dot: 'dot.svg'";
|
749 |
|
750 | return JSMapping;
|
751 |
|
752 | }).call(this);
|
753 |
|
754 | CoffeeMapping = (function() {
|
755 | class CoffeeMapping extends JSMapping {
|
756 | parse(data) {
|
757 | return super.parse(require('coffeescript').compile(data, {
|
758 | bare: true,
|
759 | filename: this.filename,
|
760 | sourceFiles: [this.filename],
|
761 | inlineMap: true
|
762 | }));
|
763 | }
|
764 |
|
765 | };
|
766 |
|
767 | CoffeeMapping.title = "CoffeeScript mapping file";
|
768 |
|
769 | CoffeeMapping.help = "Object mapping symbol names to SYMBOL e.g. dot: 'dot.svg'";
|
770 |
|
771 | return CoffeeMapping;
|
772 |
|
773 | }).call(this);
|
774 |
|
775 |
|
776 |
|
777 |
|
778 |
|
779 |
|
780 |
|
781 |
|
782 |
|
783 |
|
784 |
|
785 |
|
786 |
|
787 |
|
788 |
|
789 |
|
790 |
|
791 |
|
792 | Mappings = class Mappings {
|
793 | constructor(maps = []) {
|
794 | this.maps = maps;
|
795 | }
|
796 |
|
797 | push(map) {
|
798 | return this.maps.push(map);
|
799 | }
|
800 |
|
801 | lookup(key) {
|
802 | var i, k, ref, value;
|
803 | if (!this.maps.length) {
|
804 | return;
|
805 | }
|
806 | for (i = k = ref = this.maps.length - 1; (ref <= 0 ? k <= 0 : k >= 0); i = ref <= 0 ? ++k : --k) {
|
807 | value = this.maps[i].lookup(key);
|
808 | if (value != null) {
|
809 | return value;
|
810 | }
|
811 | }
|
812 | return void 0;
|
813 | }
|
814 |
|
815 | };
|
816 |
|
817 | blankCells = {
|
818 | '': true,
|
819 | ' ': true
|
820 | };
|
821 |
|
822 | allBlank = function(list) {
|
823 | var k, len, x;
|
824 | for (k = 0, len = list.length; k < len; k++) {
|
825 | x = list[k];
|
826 | if ((x != null) && !(x in blankCells)) {
|
827 | return false;
|
828 | }
|
829 | }
|
830 | return true;
|
831 | };
|
832 |
|
833 | Drawing = class Drawing extends Input {
|
834 | load(data) {
|
835 | var cell, j, k, l, len, len1, row;
|
836 |
|
837 | data = (function() {
|
838 | var k, len, results;
|
839 | results = [];
|
840 | for (k = 0, len = data.length; k < len; k++) {
|
841 | row = data[k];
|
842 | results.push((function() {
|
843 | var l, len1, results1;
|
844 | results1 = [];
|
845 | for (l = 0, len1 = row.length; l < len1; l++) {
|
846 | cell = row[l];
|
847 | results1.push(cell);
|
848 | }
|
849 | return results1;
|
850 | })());
|
851 | }
|
852 | return results;
|
853 | })();
|
854 | if (!Drawing.keepMargins) {
|
855 |
|
856 | while (data.length > 0 && allBlank(data[0])) {
|
857 | data.shift();
|
858 | }
|
859 |
|
860 | while (data.length > 0 && allBlank(data[data.length - 1])) {
|
861 | data.pop();
|
862 | }
|
863 | if (data.length > 0) {
|
864 |
|
865 | while (allBlank((function() {
|
866 | var l, len1, results;
|
867 | results = [];
|
868 | for (l = 0, len1 = data.length; l < len1; l++) {
|
869 | row = data[l];
|
870 | results.push(row[0]);
|
871 | }
|
872 | return results;
|
873 | })())) {
|
874 | for (k = 0, len = data.length; k < len; k++) {
|
875 | row = data[k];
|
876 | row.shift();
|
877 | }
|
878 | }
|
879 |
|
880 | j = Math.max(...((function() {
|
881 | var l, len1, results;
|
882 | results = [];
|
883 | for (l = 0, len1 = data.length; l < len1; l++) {
|
884 | row = data[l];
|
885 | results.push(row.length);
|
886 | }
|
887 | return results;
|
888 | })()));
|
889 | while (j >= 0 && allBlank((function() {
|
890 | var len2, m, results;
|
891 | results = [];
|
892 | for (m = 0, len2 = data.length; m < len2; m++) {
|
893 | row = data[m];
|
894 | results.push(row[j]);
|
895 | }
|
896 | return results;
|
897 | })())) {
|
898 | for (l = 0, len1 = data.length; l < len1; l++) {
|
899 | row = data[l];
|
900 | if (j < row.length) {
|
901 | row.pop();
|
902 | }
|
903 | }
|
904 | j--;
|
905 | }
|
906 | }
|
907 | }
|
908 | return this.data = data;
|
909 | }
|
910 |
|
911 | writeSVG(mappings, filename) {
|
912 |
|
913 | if (filename == null) {
|
914 | filename = path.parse(this.filename);
|
915 | if (filename.ext === '.svg') {
|
916 | filename.base += '.svg';
|
917 | } else {
|
918 | filename.base = filename.base.slice(0, -filename.ext.length) + '.svg';
|
919 | }
|
920 | filename = path.format(filename);
|
921 | }
|
922 | console.log('->', filename);
|
923 | fs.writeFileSync(filename, this.renderSVG(mappings));
|
924 | return filename;
|
925 | }
|
926 |
|
927 | renderSVGDOM(mappings) {
|
928 | var attribute, cell, child, colWidths, coordsRow, doc, dx, dy, i, j, k, key, l, lastSymbol, len, len1, len2, len3, len4, len5, len6, level, levelOrder, levels, m, missing, n, name, node, o, p, q, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, ref9, row, row2, rowHeight, scaleX, scaleY, svg, symbol, symbolsByKey, use, viewBox, x, y;
|
929 | |
930 |
|
931 |
|
932 |
|
933 |
|
934 |
|
935 | DynamicSymbol.resetAll();
|
936 | doc = domImplementation.createDocument(SVGNS, 'svg');
|
937 | svg = doc.documentElement;
|
938 | svg.setAttribute('xmlns:xlink', XLINKNS);
|
939 | svg.setAttribute('version', '1.1');
|
940 |
|
941 |
|
942 | missing = {};
|
943 | this.symbols = (function() {
|
944 | var k, len, ref, results;
|
945 | ref = this.data;
|
946 | results = [];
|
947 | for (k = 0, len = ref.length; k < len; k++) {
|
948 | row = ref[k];
|
949 | results.push((function() {
|
950 | var l, len1, results1;
|
951 | results1 = [];
|
952 | for (l = 0, len1 = row.length; l < len1; l++) {
|
953 | cell = row[l];
|
954 | symbol = mappings.lookup(cell);
|
955 | if (symbol != null) {
|
956 | results1.push(lastSymbol = symbol);
|
957 | } else {
|
958 | missing[cell] = true;
|
959 | results1.push(unrecognizedSymbol);
|
960 | }
|
961 | }
|
962 | return results1;
|
963 | })());
|
964 | }
|
965 | return results;
|
966 | }).call(this);
|
967 | missing = (function() {
|
968 | var results;
|
969 | results = [];
|
970 | for (key in missing) {
|
971 | if (!hasProp.call(missing, key)) continue;
|
972 | results.push(`'${key}'`);
|
973 | }
|
974 | return results;
|
975 | })();
|
976 | if (missing.length) {
|
977 | console.warn("Failed to recognize symbols:", missing.join(', '));
|
978 | }
|
979 |
|
980 | symbolsByKey = {};
|
981 | this.symbols = (function() {
|
982 | var k, len, ref, results;
|
983 | ref = this.symbols;
|
984 | results = [];
|
985 | for (i = k = 0, len = ref.length; k < len; i = ++k) {
|
986 | row = ref[i];
|
987 | results.push((function() {
|
988 | var l, len1, results1;
|
989 | results1 = [];
|
990 | for (j = l = 0, len1 = row.length; l < len1; j = ++l) {
|
991 | symbol = row[j];
|
992 | if (symbol.usesContext) {
|
993 | symbol = symbol.use(new Context(this, i, j));
|
994 | } else {
|
995 | symbol = symbol.use();
|
996 | }
|
997 | if (!(symbol.key in symbolsByKey)) {
|
998 | symbolsByKey[symbol.key] = symbol;
|
999 | } else if (symbolsByKey[symbol.key] === !symbol) {
|
1000 | console.warn(`Multiple symbols with key ${symbol.key}`);
|
1001 | }
|
1002 | results1.push(symbol);
|
1003 | }
|
1004 | return results1;
|
1005 | }).call(this));
|
1006 | }
|
1007 | return results;
|
1008 | }).call(this);
|
1009 |
|
1010 | for (key in symbolsByKey) {
|
1011 | symbol = symbolsByKey[key];
|
1012 | if (symbol == null) {
|
1013 | continue;
|
1014 | }
|
1015 | svg.appendChild(node = doc.createElementNS(SVGNS, 'symbol'));
|
1016 | node.setAttribute('id', symbol.id());
|
1017 | if ((ref = symbol.xml.documentElement.tagName) === 'svg' || ref === 'symbol') {
|
1018 | ref1 = symbol.xml.documentElement.attributes;
|
1019 |
|
1020 | for (k = 0, len = ref1.length; k < len; k++) {
|
1021 | attribute = ref1[k];
|
1022 | if (!(((ref2 = attribute.name) === 'version' || ref2 === 'id') || attribute.name.slice(0, 5) === 'xmlns')) {
|
1023 | node.setAttribute(attribute.name, attribute.value);
|
1024 | }
|
1025 | }
|
1026 | ref3 = symbol.xml.documentElement.childNodes;
|
1027 | for (l = 0, len1 = ref3.length; l < len1; l++) {
|
1028 | child = ref3[l];
|
1029 | node.appendChild(child.cloneNode(true));
|
1030 | }
|
1031 | } else {
|
1032 | node.appendChild(symbol.xml.documentElement.cloneNode(true));
|
1033 | }
|
1034 |
|
1035 | if (symbol.viewBox != null) {
|
1036 | node.setAttribute('viewBox', symbol.viewBox);
|
1037 | }
|
1038 | }
|
1039 |
|
1040 | viewBox = [
|
1041 | 0,
|
1042 | 0,
|
1043 | 0,
|
1044 | 0
|
1045 | ];
|
1046 | levels = {};
|
1047 | y = 0;
|
1048 | colWidths = {};
|
1049 | this.coords = [];
|
1050 | ref4 = this.symbols;
|
1051 | for (i = m = 0, len2 = ref4.length; m < len2; i = ++m) {
|
1052 | row = ref4[i];
|
1053 | this.coords.push(coordsRow = []);
|
1054 | rowHeight = 0;
|
1055 | for (n = 0, len3 = row.length; n < len3; n++) {
|
1056 | symbol = row[n];
|
1057 | if (!symbol.autoHeight) {
|
1058 | if (symbol.height > rowHeight) {
|
1059 | rowHeight = symbol.height;
|
1060 | }
|
1061 | }
|
1062 | }
|
1063 | x = 0;
|
1064 | for (j = o = 0, len4 = row.length; o < len4; j = ++o) {
|
1065 | symbol = row[j];
|
1066 | coordsRow.push({x, y});
|
1067 | if (symbol == null) {
|
1068 | continue;
|
1069 | }
|
1070 | if (levels[name = symbol.zIndex] == null) {
|
1071 | levels[name] = [];
|
1072 | }
|
1073 | levels[symbol.zIndex].push(use = doc.createElementNS(SVGNS, 'use'));
|
1074 | use.setAttribute('xlink:href', '#' + symbol.id());
|
1075 | use.setAttributeNS(SVGNS, 'x', x);
|
1076 | use.setAttributeNS(SVGNS, 'y', y);
|
1077 | scaleX = scaleY = 1;
|
1078 | if (symbol.autoWidth) {
|
1079 | if (colWidths[j] == null) {
|
1080 | colWidths[j] = Math.max(0, ...((function() {
|
1081 | var len5, p, ref5, results;
|
1082 | ref5 = this.symbols;
|
1083 | results = [];
|
1084 | for (p = 0, len5 = ref5.length; p < len5; p++) {
|
1085 | row2 = ref5[p];
|
1086 | if ((row2[j] != null) && !row2[j].autoWidth) {
|
1087 | results.push(row2[j].width);
|
1088 | }
|
1089 | }
|
1090 | return results;
|
1091 | }).call(this)));
|
1092 | }
|
1093 | if (symbol.width !== 0) {
|
1094 | scaleX = colWidths[j] / symbol.width;
|
1095 | }
|
1096 | if (!symbol.autoHeight) {
|
1097 | scaleY = scaleX;
|
1098 | }
|
1099 | }
|
1100 | if (symbol.autoHeight) {
|
1101 | if (symbol.height !== 0) {
|
1102 | scaleY = rowHeight / symbol.height;
|
1103 | }
|
1104 | if (!symbol.autoWidth) {
|
1105 | scaleX = scaleY;
|
1106 | }
|
1107 | }
|
1108 |
|
1109 |
|
1110 | use.setAttributeNS(SVGNS, 'width', ((ref5 = (ref6 = symbol.viewBox) != null ? ref6[2] : void 0) != null ? ref5 : symbol.width) * scaleX);
|
1111 | use.setAttributeNS(SVGNS, 'height', ((ref7 = (ref8 = symbol.viewBox) != null ? ref8[3] : void 0) != null ? ref7 : symbol.height) * scaleY);
|
1112 | if (symbol.overflowBox != null) {
|
1113 | dx = (symbol.overflowBox[0] - symbol.viewBox[0]) * scaleX;
|
1114 | dy = (symbol.overflowBox[1] - symbol.viewBox[1]) * scaleY;
|
1115 | viewBox[0] = Math.min(viewBox[0], x + dx);
|
1116 | viewBox[1] = Math.min(viewBox[1], y + dy);
|
1117 | viewBox[2] = Math.max(viewBox[2], x + dx + symbol.overflowBox[2] * scaleX);
|
1118 | viewBox[3] = Math.max(viewBox[3], y + dy + symbol.overflowBox[3] * scaleY);
|
1119 | }
|
1120 | x += symbol.width * scaleX;
|
1121 | viewBox[2] = Math.max(viewBox[2], x);
|
1122 | }
|
1123 | y += rowHeight;
|
1124 | viewBox[3] = Math.max(viewBox[3], y);
|
1125 | }
|
1126 |
|
1127 | viewBox[2] = viewBox[2] - viewBox[0];
|
1128 | viewBox[3] = viewBox[3] - viewBox[1];
|
1129 |
|
1130 | levelOrder = ((function() {
|
1131 | var results;
|
1132 | results = [];
|
1133 | for (level in levels) {
|
1134 | results.push(level);
|
1135 | }
|
1136 | return results;
|
1137 | })()).sort(function(x, y) {
|
1138 | return x - y;
|
1139 | });
|
1140 | for (p = 0, len5 = levelOrder.length; p < len5; p++) {
|
1141 | level = levelOrder[p];
|
1142 | ref9 = levels[level];
|
1143 | for (q = 0, len6 = ref9.length; q < len6; q++) {
|
1144 | node = ref9[q];
|
1145 | svg.appendChild(node);
|
1146 | }
|
1147 | }
|
1148 | svg.setAttributeNS(SVGNS, 'viewBox', viewBox.join(' '));
|
1149 | svg.setAttributeNS(SVGNS, 'width', this.width = viewBox[2]);
|
1150 | svg.setAttributeNS(SVGNS, 'height', this.height = viewBox[3]);
|
1151 | svg.setAttributeNS(SVGNS, 'preserveAspectRatio', 'xMinYMin meet');
|
1152 | return doc;
|
1153 | }
|
1154 |
|
1155 | renderSVG(mappings) {
|
1156 | var out;
|
1157 | out = new XMLSerializer().serializeToString(this.renderSVGDOM(mappings));
|
1158 |
|
1159 |
|
1160 | out = out.replace(/\sxmlns:xlink=""/g, '');
|
1161 | out = prettyXML(out, {
|
1162 | newline: '\n'
|
1163 | });
|
1164 | return `<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
1165 | <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
1166 | ` + out;
|
1167 | }
|
1168 |
|
1169 | renderTeX(filename) {
|
1170 | var anchor, basename, child, content, i, j, k, l, len, len1, len2, lines, m, ref, ref1, ref2, ref3, row, symbol, text, tx, ty, wrap, x, y;
|
1171 |
|
1172 | filename = path.parse(filename);
|
1173 | basename = filename.base.slice(0, -filename.ext.length);
|
1174 |
|
1175 |
|
1176 | lines = [
|
1177 | `%% Creator: svgtiler ${svgtiler.version}, https://github.com/edemaine/svgtiler
|
1178 | %% This LaTeX file includes and overlays text on top of companion file
|
1179 | %% ${basename}.pdf/.png
|
1180 | %%
|
1181 | %% Instead of \\includegraphics, include this figure via
|
1182 | %% \\input{${filename.base}}
|
1183 | %% You can scale the image by first defining \\svg{width,height,scale}:
|
1184 | %% \\def\\svgwidth{\\linewidth} % full width
|
1185 | %% or
|
1186 | %% \\def\\svgheight{5in}
|
1187 | %% or
|
1188 | %% \\def\\svgscale{0.5} % 50%
|
1189 | %% (If multiple are specified, the first in the list above takes priority.)
|
1190 | %%
|
1191 | %% If this file resides in another directory from the root .tex file,
|
1192 | %% you need to help it find its auxiliary .pdf/.png file via one of the
|
1193 | %% following options (any one will do):
|
1194 | %% 1. \\usepackage{currfile} so that this file can find its own directory.
|
1195 | %% 2. \\usepackage{import} and \\import{path/to/file/}{${filename.base}}
|
1196 | %% instead of \\import{${filename.base}}
|
1197 | %% 3. \\graphicspath{{path/to/file/}} % note extra braces and trailing slash
|
1198 | %%
|
1199 | \\begingroup
|
1200 | \\providecommand\\color[2][]{%
|
1201 | \\errmessage{You should load package 'color.sty' to render color in svgtiler text.}%
|
1202 | \\renewcommand\\color[2][]{}%
|
1203 | }%
|
1204 | \\ifx\\currfiledir\\undefined
|
1205 | \\def\\currfiledir{}%
|
1206 | \\fi
|
1207 | \\ifx\\svgwidth\\undefined
|
1208 | \\ifx\\svgheight\\undefined
|
1209 | \\unitlength=0.75bp\\relax % 1px (SVG unit) = 0.75bp (SVG pts)
|
1210 | \\ifx\\svgscale\\undefined\\else
|
1211 | \\ifx\\real\\undefined % in case calc.sty not loaded
|
1212 | \\unitlength=\\svgscale \\unitlength
|
1213 | \\else
|
1214 | \\setlength{\\unitlength}{\\unitlength * \\real{\\svgscale}}%
|
1215 | \\fi
|
1216 | \\fi
|
1217 | \\else
|
1218 | \\unitlength=\\svgheight
|
1219 | \\unitlength=${1 / this.height}\\unitlength % divide by image height
|
1220 | \\fi
|
1221 | \\else
|
1222 | \\unitlength=\\svgwidth
|
1223 | \\unitlength=${1 / this.width}\\unitlength % divide by image width
|
1224 | \\fi
|
1225 | \\def\\clap#1{\\hbox to 0pt{\\hss#1\\hss}}%
|
1226 | \\begin{picture}(${this.width},${this.height})%
|
1227 | \\put(0,0){\\includegraphics[width=${this.width}\\unitlength]{\\currfiledir ${basename}}}%`
|
1228 | ];
|
1229 | ref = this.symbols;
|
1230 | for (i = k = 0, len = ref.length; k < len; i = ++k) {
|
1231 | row = ref[i];
|
1232 | for (j = l = 0, len1 = row.length; l < len1; j = ++l) {
|
1233 | symbol = row[j];
|
1234 | ({x, y} = this.coords[i][j]);
|
1235 | ref1 = symbol.text;
|
1236 | for (m = 0, len2 = ref1.length; m < len2; m++) {
|
1237 | text = ref1[m];
|
1238 | tx = (ref2 = parseNum(text.getAttribute('x'))) != null ? ref2 : 0;
|
1239 | ty = (ref3 = parseNum(text.getAttribute('y'))) != null ? ref3 : 0;
|
1240 | content = ((function() {
|
1241 | var len3, n, ref4, results;
|
1242 | ref4 = text.childNodes;
|
1243 | // TEXT_NODE
|
1244 | results = [];
|
1245 | for (n = 0, len3 = ref4.length; n < len3; n++) {
|
1246 | child = ref4[n];
|
1247 | if (child.nodeType === 3) {
|
1248 | results.push(child.data);
|
1249 | }
|
1250 | }
|
1251 | return results;
|
1252 | })()).join('');
|
1253 | anchor = attributeOrStyle(text, 'text-anchor');
|
1254 | if (/^middle\b/.test(anchor)) {
|
1255 | wrap = '\\clap{';
|
1256 | } else if (/^end\b/.test(anchor)) {
|
1257 | wrap = '\\rlap{'; //if /^start\b/.test anchor # default
|
1258 | } else {
|
1259 | wrap = '\\llap{';
|
1260 | }
|
1261 | // "@height -" is to flip between y down (SVG) and y up (picture)
|
1262 | lines.push(` \\put(${x + tx},${this.height - (y + ty)}){\\color{${attributeOrStyle(text, 'fill') || 'black'}}${wrap}${content}${wrap && '}'}}%`);
|
1263 | }
|
1264 | }
|
1265 | }
|
1266 | lines.push(` \\end{picture}%
|
1267 | \\endgroup`, ''); // trailing newline
|
1268 | return lines.join('\n');
|
1269 | }
|
1270 |
|
1271 | writeTeX(filename) {
|
1272 | /*
|
1273 | Must be called *after* `writeSVG`.
|
1274 | Default filename is the input filename with extension replaced by .svg_tex
|
1275 | (analogous to .pdf_tex from Inkscape's --export-latex feature, but noting
|
1276 | that the text is extracted from the SVG not the PDF, and that this file
|
1277 | works with both .pdf and .png auxiliary files).
|
1278 | */
|
1279 | if (filename == null) {
|
1280 | filename = path.parse(this.filename);
|
1281 | if (filename.ext === '.svg_tex') {
|
1282 | filename.base += '.svg_tex';
|
1283 | } else {
|
1284 | filename.base = filename.base.slice(0, -filename.ext.length) + '.svg_tex';
|
1285 | }
|
1286 | filename = path.format(filename);
|
1287 | }
|
1288 | console.log(' &', filename);
|
1289 | fs.writeFileSync(filename, this.renderTeX(filename));
|
1290 | return filename;
|
1291 | }
|
1292 |
|
1293 | };
|
1294 |
|
1295 | ASCIIDrawing = (function() {
|
1296 | class ASCIIDrawing extends Drawing {
|
1297 | parse(data) {
|
1298 | var line;
|
1299 | return this.load((function() {
|
1300 | var k, len, ref, results;
|
1301 | ref = splitIntoLines(data);
|
1302 | results = [];
|
1303 | for (k = 0, len = ref.length; k < len; k++) {
|
1304 | line = ref[k];
|
1305 | results.push(graphemeSplitter.splitGraphemes(line));
|
1306 | }
|
1307 | return results;
|
1308 | })());
|
1309 | }
|
1310 |
|
1311 | };
|
1312 |
|
1313 | ASCIIDrawing.title = "ASCII drawing (one character per symbol)";
|
1314 |
|
1315 | return ASCIIDrawing;
|
1316 |
|
1317 | }).call(this);
|
1318 |
|
1319 | DSVDrawing = class DSVDrawing extends Drawing {
|
1320 | parse(data) {
|
1321 | var ref;
|
1322 | //# Remove trailing newline / final blank line.
|
1323 | if (data.slice(-2) === '\r\n') {
|
1324 | data = data.slice(0, -2);
|
1325 | } else if ((ref = data.slice(-1)) === '\r' || ref === '\n') {
|
1326 | data = data.slice(0, -1);
|
1327 | }
|
1328 | //# CSV parser.
|
1329 | return this.load(require('csv-parse/lib/sync')(data, {
|
1330 | delimiter: this.constructor.delimiter,
|
1331 | relax_column_count: true
|
1332 | }));
|
1333 | }
|
1334 |
|
1335 | };
|
1336 |
|
1337 | SSVDrawing = (function() {
|
1338 | class SSVDrawing extends DSVDrawing {
|
1339 | parse(data) {
|
1340 | //# Coallesce non-newline whitespace into single space
|
1341 | return super.parse(data.replace(/[ \t\f\v]+/g, ' '));
|
1342 | }
|
1343 |
|
1344 | };
|
1345 |
|
1346 | SSVDrawing.title = "Space-delimiter drawing (one word per symbol)";
|
1347 |
|
1348 | SSVDrawing.delimiter = ' ';
|
1349 |
|
1350 | return SSVDrawing;
|
1351 |
|
1352 | }).call(this);
|
1353 |
|
1354 | CSVDrawing = (function() {
|
1355 | class CSVDrawing extends DSVDrawing {};
|
1356 |
|
1357 | CSVDrawing.title = "Comma-separated drawing (spreadsheet export)";
|
1358 |
|
1359 | CSVDrawing.delimiter = ',';
|
1360 |
|
1361 | return CSVDrawing;
|
1362 |
|
1363 | }).call(this);
|
1364 |
|
1365 | TSVDrawing = (function() {
|
1366 | class TSVDrawing extends DSVDrawing {};
|
1367 |
|
1368 | TSVDrawing.title = "Tab-separated drawing (spreadsheet export)";
|
1369 |
|
1370 | TSVDrawing.delimiter = '\t';
|
1371 |
|
1372 | return TSVDrawing;
|
1373 |
|
1374 | }).call(this);
|
1375 |
|
1376 | Drawings = (function() {
|
1377 | class Drawings extends Input {
|
1378 | load(datas) {
|
1379 | var data, drawing;
|
1380 | return this.drawings = (function() {
|
1381 | var k, len, results;
|
1382 | results = [];
|
1383 | for (k = 0, len = datas.length; k < len; k++) {
|
1384 | data = datas[k];
|
1385 | drawing = new Drawing();
|
1386 | drawing.filename = this.filename;
|
1387 | drawing.subname = data.subname;
|
1388 | drawing.load(data);
|
1389 | results.push(drawing);
|
1390 | }
|
1391 | return results;
|
1392 | }).call(this);
|
1393 | }
|
1394 |
|
1395 | subfilename(extension, drawing) {
|
1396 | var filename2;
|
1397 | if (this.drawings.length > 1) {
|
1398 | filename2 = path.parse(typeof filename !== "undefined" && filename !== null ? filename : this.filename);
|
1399 | filename2.base = filename2.base.slice(0, -filename2.ext.length);
|
1400 | filename2.base += this.constructor.filenameSeparator + drawing.subname;
|
1401 | filename2.base += extension;
|
1402 | return path.format(filename2);
|
1403 | } else {
|
1404 | if (drawing != null) {
|
1405 | drawing.filename = this.filename; //# use Drawing default if not filename?
|
1406 | }
|
1407 | return filename;
|
1408 | }
|
1409 | }
|
1410 |
|
1411 | writeSVG(mappings, filename) {
|
1412 | var drawing, k, len, ref, results;
|
1413 | ref = this.drawings;
|
1414 | results = [];
|
1415 | for (k = 0, len = ref.length; k < len; k++) {
|
1416 | drawing = ref[k];
|
1417 | results.push(drawing.writeSVG(mappings, this.subfilename('.svg', drawing)));
|
1418 | }
|
1419 | return results;
|
1420 | }
|
1421 |
|
1422 | writeTeX(filename) {
|
1423 | var drawing, k, len, ref, results;
|
1424 | ref = this.drawings;
|
1425 | results = [];
|
1426 | for (k = 0, len = ref.length; k < len; k++) {
|
1427 | drawing = ref[k];
|
1428 | results.push(drawing.writeTeX(this.subfilename('.svg_tex', drawing)));
|
1429 | }
|
1430 | return results;
|
1431 | }
|
1432 |
|
1433 | };
|
1434 |
|
1435 | Drawings.filenameSeparator = '_';
|
1436 |
|
1437 | return Drawings;
|
1438 |
|
1439 | }).call(this);
|
1440 |
|
1441 | XLSXDrawings = (function() {
|
1442 | class XLSXDrawings extends Drawings {
|
1443 | parse(data) {
|
1444 | var rows, sheet, sheetInfo, subname, workbook, xlsx;
|
1445 | xlsx = require('xlsx');
|
1446 | workbook = xlsx.read(data, {
|
1447 | type: 'binary'
|
1448 | });
|
1449 | //# https://www.npmjs.com/package/xlsx#common-spreadsheet-format
|
1450 | return this.load((function() {
|
1451 | var k, len, ref, results;
|
1452 | ref = workbook.Workbook.Sheets;
|
1453 | results = [];
|
1454 | for (k = 0, len = ref.length; k < len; k++) {
|
1455 | sheetInfo = ref[k];
|
1456 | subname = sheetInfo.name;
|
1457 | sheet = workbook.Sheets[subname];
|
1458 | //# 0 = Visible, 1 = Hidden, 2 = Very Hidden
|
1459 | //# https://sheetjs.gitbooks.io/docs/#sheet-visibility
|
1460 | if (sheetInfo.Hidden && !Drawings.keepHidden) {
|
1461 | continue;
|
1462 | }
|
1463 | if (subname.length === 31) {
|
1464 | console.warn(`Warning: Sheet '${subname}' has length exactly 31, which may be caused by Google Sheets export truncation`);
|
1465 | }
|
1466 | rows = xlsx.utils.sheet_to_json(sheet, {
|
1467 | header: 1,
|
1468 | defval: ''
|
1469 | });
|
1470 | rows.subname = subname;
|
1471 | results.push(rows);
|
1472 | }
|
1473 | return results;
|
1474 | })());
|
1475 | }
|
1476 |
|
1477 | };
|
1478 |
|
1479 | XLSXDrawings.encoding = 'binary';
|
1480 |
|
1481 | XLSXDrawings.title = "Spreadsheet drawing(s) (Excel/OpenDocument/Lotus/dBASE)";
|
1482 |
|
1483 | return XLSXDrawings;
|
1484 |
|
1485 | }).call(this);
|
1486 |
|
1487 | Context = class Context {
|
1488 | constructor(drawing1, i1, j1) {
|
1489 | var ref, ref1;
|
1490 | this.drawing = drawing1;
|
1491 | this.i = i1;
|
1492 | this.j = j1;
|
1493 | this.symbols = this.drawing.symbols;
|
1494 | this.filename = this.drawing.filename;
|
1495 | this.subname = this.drawing.subname;
|
1496 | this.symbol = (ref = this.symbols[this.i]) != null ? ref[this.j] : void 0;
|
1497 | this.key = (ref1 = this.symbol) != null ? ref1.key : void 0;
|
1498 | }
|
1499 |
|
1500 | neighbor(dj, di) {
|
1501 | return new Context(this.drawing, this.i + di, this.j + dj);
|
1502 | }
|
1503 |
|
1504 | includes(...args) {
|
1505 | return (this.symbol != null) && this.symbol.includes(...args);
|
1506 | }
|
1507 |
|
1508 | row(di = 0) {
|
1509 | var i, j, k, len, ref, ref1, results, symbol;
|
1510 | i = this.i + di;
|
1511 | ref1 = (ref = this.symbols[i]) != null ? ref : [];
|
1512 | results = [];
|
1513 | for (j = k = 0, len = ref1.length; k < len; j = ++k) {
|
1514 | symbol = ref1[j];
|
1515 | results.push(new Context(this.drawing, i, j));
|
1516 | }
|
1517 | return results;
|
1518 | }
|
1519 |
|
1520 | column(dj = 0) {
|
1521 | var i, j, k, len, ref, results, row;
|
1522 | j = this.j + dj;
|
1523 | ref = this.symbols;
|
1524 | results = [];
|
1525 | for (i = k = 0, len = ref.length; k < len; i = ++k) {
|
1526 | row = ref[i];
|
1527 | results.push(new Context(this.drawing, i, j));
|
1528 | }
|
1529 | return results;
|
1530 | }
|
1531 |
|
1532 | };
|
1533 |
|
1534 | extensionMap = {
|
1535 | '.txt': ASCIIMapping,
|
1536 | '.js': JSMapping,
|
1537 | '.jsx': JSMapping,
|
1538 | '.coffee': CoffeeMapping,
|
1539 | '.cjsx': CoffeeMapping,
|
1540 | '.asc': ASCIIDrawing,
|
1541 | '.ssv': SSVDrawing,
|
1542 | '.csv': CSVDrawing,
|
1543 | '.tsv': TSVDrawing,
|
1544 | //# Parsable by xlsx package:
|
1545 | '.xlsx': XLSXDrawings, //# Excel 2007+ XML Format
|
1546 | '.xlsm': XLSXDrawings, //# Excel 2007+ Macro XML Format
|
1547 | '.xlsb': XLSXDrawings, //# Excel 2007+ Binary Format
|
1548 | '.xls': XLSXDrawings, //# Excel 2.0 or 2003-2004 (SpreadsheetML)
|
1549 | '.ods': XLSXDrawings, //# OpenDocument Spreadsheet
|
1550 | '.fods': XLSXDrawings, //# Flat OpenDocument Spreadsheet
|
1551 | '.dif': XLSXDrawings, //# Data Interchange Format (DIF)
|
1552 | '.prn': XLSXDrawings, //# Lotus Formatted Text
|
1553 | '.dbf': XLSXDrawings //# dBASE II/III/IV / Visual FoxPro
|
1554 | };
|
1555 |
|
1556 | sanitize = true;
|
1557 |
|
1558 | bufferSize = 16 * 1024;
|
1559 |
|
1560 | postprocess = function(format, filename) {
|
1561 | var buffer, e, file, fileSize, match, position, readSize, string;
|
1562 | if (!sanitize) {
|
1563 | return;
|
1564 | }
|
1565 | try {
|
1566 | switch (format) {
|
1567 | case 'pdf':
|
1568 | //# Blank out /CreationDate in PDF for easier version control.
|
1569 | //# Replace these commands with spaces to avoid in-file pointer errors.
|
1570 | buffer = Buffer.alloc(bufferSize);
|
1571 | fileSize = fs.statSync(filename).size;
|
1572 | position = Math.max(0, fileSize - bufferSize);
|
1573 | file = fs.openSync(filename, 'r+');
|
1574 | readSize = fs.readSync(file, buffer, 0, bufferSize, position);
|
1575 | string = buffer.toString('binary'); //# must use single-byte encoding!
|
1576 | match = /\/CreationDate\s*\((?:[^()\\]|\\[^])*\)/.exec(string);
|
1577 | if (match != null) {
|
1578 | fs.writeSync(file, ' '.repeat(match[0].length), position + match.index);
|
1579 | }
|
1580 | return fs.closeSync(file);
|
1581 | }
|
1582 | } catch (error1) {
|
1583 | e = error1;
|
1584 | return console.log(`Failed to postprocess '${filename}': ${e}`);
|
1585 | }
|
1586 | };
|
1587 |
|
1588 | convertSVG = function(format, svg, sync) {
|
1589 | var args, child_process, filename, output, preprocess, result;
|
1590 | child_process = require('child_process');
|
1591 | filename = path.parse(svg);
|
1592 | if (filename.ext === `.${format}`) {
|
1593 | filename.base += `.${format}`;
|
1594 | } else {
|
1595 | filename.base = `${filename.base.slice(0, -filename.ext.length)}.${format}`;
|
1596 | }
|
1597 | output = path.format(filename);
|
1598 | //# Workaround relative paths not working in MacOS distribution of Inkscape
|
1599 | //# [https://bugs.launchpad.net/inkscape/+bug/181639]
|
1600 | if (process.platform === 'darwin') {
|
1601 | preprocess = path.resolve;
|
1602 | } else {
|
1603 | preprocess = function(x) {
|
1604 | return x;
|
1605 | };
|
1606 | }
|
1607 | args = ['-z', `--file=${preprocess(svg)}`, `--export-${format}=${preprocess(output)}`];
|
1608 | if (sync) {
|
1609 | //# In sychronous mode, we let inkscape directly output its error messages,
|
1610 | //# and add warnings about any failures that occur.
|
1611 | console.log('=>', output);
|
1612 | result = child_process.spawnSync('inkscape', args, {
|
1613 | stdio: 'inherit'
|
1614 | });
|
1615 | if (result.error) {
|
1616 | return console.log(result.error.message);
|
1617 | } else if (result.status || result.signal) {
|
1618 | return console.log(`:-( ${output} FAILED`);
|
1619 | } else {
|
1620 | return postprocess(format, output);
|
1621 | }
|
1622 | } else {
|
1623 | //# In asychronous mode, we capture inkscape's outputs, and print them only
|
1624 | //# when the process has finished, along with which file failed, to avoid
|
1625 | //# mixing up messages from parallel executions.
|
1626 | return function(resolve) {
|
1627 | var inkscape, out;
|
1628 | console.log('=>', output);
|
1629 | inkscape = require('child_process').spawn('inkscape', args);
|
1630 | out = '';
|
1631 | inkscape.stdout.on('data', function(buf) {
|
1632 | return out += buf;
|
1633 | });
|
1634 | inkscape.stderr.on('data', function(buf) {
|
1635 | return out += buf;
|
1636 | });
|
1637 | inkscape.on('error', function(error) {
|
1638 | return console.log(error.message);
|
1639 | });
|
1640 | return inkscape.on('exit', function(status, signal) {
|
1641 | if (status || signal) {
|
1642 | console.log(`:-( ${output} FAILED:`);
|
1643 | console.log(out);
|
1644 | } else {
|
1645 | postprocess(format, output);
|
1646 | }
|
1647 | return resolve();
|
1648 | });
|
1649 | };
|
1650 | }
|
1651 | };
|
1652 |
|
1653 | help = function() {
|
1654 | var extension, klass, ref;
|
1655 | console.log(`svgtiler ${(ref = svgtiler.version) != null ? ref : "(web)"}
|
1656 | Usage: ${process.argv[1]} (...options and filenames...)
|
1657 | Documentation: https:
|
1658 |
|
1659 | Optional arguments:
|
1660 | --help Show this help message and exit.
|
1661 | -m / --margin Don't delete blank extreme rows/columns
|
1662 | --hidden Process hidden sheets within spreadsheet files
|
1663 | --tw TILE_WIDTH / --tile-width TILE_WIDTH
|
1664 | Force all symbol tiles to have specified width
|
1665 | --th TILE_HEIGHT / --tile-height TILE_HEIGHT
|
1666 | Force all symbol tiles to have specified height
|
1667 | -p / --pdf Convert output SVG files to PDF via Inkscape
|
1668 | -P / --png Convert output SVG files to PNG via Inkscape
|
1669 | -t / --tex Move <text> from SVG to accompanying LaTeX file.tex
|
1670 | --no-sanitize Don't sanitize PDF output by blanking out /CreationDate
|
1671 | -j N / --jobs N Run up to N Inkscape jobs in parallel
|
1672 |
|
1673 | Filename arguments: (mappings before drawings!)
|
1674 | `);
|
1675 | for (extension in extensionMap) {
|
1676 | klass = extensionMap[extension];
|
1677 | if (extension.length < 10) {
|
1678 | extension += ' '.repeat(10 - extension.length);
|
1679 | }
|
1680 | console.log(` *${extension} ${klass.title}`);
|
1681 | if (klass.help != null) {
|
1682 | console.log(` ${klass.help}`);
|
1683 | }
|
1684 | }
|
1685 | console.log(`
|
1686 | SYMBOL specifiers: (omit the quotes in anything except .js and .coffee files)
|
1687 |
|
1688 | 'filename.svg': load SVG from specified file
|
1689 | 'filename.png': include PNG image from specified file
|
1690 | 'filename.jpg': include JPEG image from specified file
|
1691 | '<svg>...</svg>': raw SVG
|
1692 | -> ...@key...: function computing SVG, with \`this\` bound to Context with
|
1693 | \`key\` (symbol name), \`i\` and \`j\` (y and x coordinates),
|
1694 | \`filename\` (drawing filename), \`subname\` (subsheet name),
|
1695 | and supporting \`neighbor\`/\`includes\`/\`row\`/\`column\` methods`);
|
1696 | //object with one or more attributes
|
1697 | return process.exit();
|
1698 | };
|
1699 |
|
1700 | main = function() {
|
1701 | var arg, args, filename, filenames, files, format, formats, i, input, jobs, k, l, len, len1, len2, m, mappings, skip, sync;
|
1702 | mappings = new Mappings();
|
1703 | args = process.argv.slice(2);
|
1704 | files = skip = 0;
|
1705 | formats = [];
|
1706 | jobs = [];
|
1707 | sync = true;
|
1708 | for (i = k = 0, len = args.length; k < len; i = ++k) {
|
1709 | arg = args[i];
|
1710 | if (skip) {
|
1711 | skip--;
|
1712 | continue;
|
1713 | }
|
1714 | switch (arg) {
|
1715 | case '-h':
|
1716 | case '--help':
|
1717 | help();
|
1718 | break;
|
1719 | case '-m':
|
1720 | case '--margin':
|
1721 | Drawing.keepMargins = true;
|
1722 | break;
|
1723 | case '--hidden':
|
1724 | Drawings.keepHidden = true;
|
1725 | break;
|
1726 | case '--tw':
|
1727 | case '--tile-width':
|
1728 | skip = 1;
|
1729 | arg = parseFloat(args[i + 1]);
|
1730 | if (arg) {
|
1731 | Symbol.forceWidth = arg;
|
1732 | } else {
|
1733 | console.warn(`Invalid argument to --tile-width: ${args[i + 1]}`);
|
1734 | }
|
1735 | break;
|
1736 | case '--th':
|
1737 | case '--tile-height':
|
1738 | skip = 1;
|
1739 | arg = parseFloat(args[i + 1]);
|
1740 | if (arg) {
|
1741 | Symbol.forceHeight = arg;
|
1742 | } else {
|
1743 | console.warn(`Invalid argument to --tile-height: ${args[i + 1]}`);
|
1744 | }
|
1745 | break;
|
1746 | case '-p':
|
1747 | case '--pdf':
|
1748 | formats.push('pdf');
|
1749 | break;
|
1750 | case '-P':
|
1751 | case '--png':
|
1752 | formats.push('png');
|
1753 | break;
|
1754 | case '-t':
|
1755 | case '--tex':
|
1756 | Symbol.texText = true;
|
1757 | break;
|
1758 | case '--no-sanitize':
|
1759 | sanitize = false;
|
1760 | break;
|
1761 | case '-j':
|
1762 | case '--jobs':
|
1763 | skip = 1;
|
1764 | arg = parseInt(args[i + 1]);
|
1765 | if (arg) {
|
1766 | jobs = new require('async-limiter')({
|
1767 | concurrency: arg
|
1768 | });
|
1769 | sync = false;
|
1770 | } else {
|
1771 | console.warn(`Invalid argument to --jobs: ${args[i + 1]}`);
|
1772 | }
|
1773 | break;
|
1774 | default:
|
1775 | files++;
|
1776 | console.log('*', arg);
|
1777 | input = Input.recognize(arg);
|
1778 | if (input instanceof Mapping) {
|
1779 | mappings.push(input);
|
1780 | } else if (input instanceof Drawing || input instanceof Drawings) {
|
1781 | filenames = input.writeSVG(mappings);
|
1782 | if (Symbol.texText) {
|
1783 | input.writeTeX(mappings);
|
1784 | }
|
1785 | for (l = 0, len1 = formats.length; l < len1; l++) {
|
1786 | format = formats[l];
|
1787 | if (typeof filenames === 'string') {
|
1788 | jobs.push(convertSVG(format, filenames, sync));
|
1789 | } else {
|
1790 | for (m = 0, len2 = filenames.length; m < len2; m++) {
|
1791 | filename = filenames[m];
|
1792 | jobs.push(convertSVG(format, filename, sync));
|
1793 | }
|
1794 | }
|
1795 | }
|
1796 | }
|
1797 | }
|
1798 | }
|
1799 | if (!files) {
|
1800 | console.log('Not enough filename arguments');
|
1801 | return help();
|
1802 | }
|
1803 | };
|
1804 |
|
1805 | exports = {Symbol, StaticSymbol, DynamicSymbol, unrecognizedSymbol, Mapping, ASCIIMapping, JSMapping, CoffeeMapping, Drawing, ASCIIDrawing, DSVDrawing, SSVDrawing, CSVDrawing, TSVDrawing, Drawings, XLSXDrawings, Input, Mappings, Context, SVGTilerException, SVGNS, XLINKNS, main};
|
1806 |
|
1807 | if (typeof module !== "undefined" && module !== null) {
|
1808 | if (module.exports == null) {
|
1809 | module.exports = exports;
|
1810 | }
|
1811 | }
|
1812 |
|
1813 | if (typeof window !== "undefined" && window !== null) {
|
1814 | if (window.svgtiler == null) {
|
1815 | window.svgtiler = exports;
|
1816 | }
|
1817 | }
|
1818 |
|
1819 | if (typeof window === "undefined" || window === null) {
|
1820 | main();
|
1821 | }
|
1822 |
|
1823 | }).call(this);
|