UNPKG

svg-cleaner

Version:

Cleaning SVG Files - A partial port of Scour to JavaScript.

344 lines (290 loc) 128 kB
<!DOCTYPE html> <html> <head> <title>svg-cleaner.js</title> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <link rel="stylesheet" media="all" href="docco.css" /> </head> <body> <div id="container"> <div id="background"></div> <table cellpadding="0" cellspacing="0"> <thead> <tr> <th class="docs"> <h1> svg-cleaner.js </h1> </th> <th class="code"> </th> </tr> </thead> <tbody> <tr id="section-1"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-1">&#182;</a> </div> <h2>SVG Cleaner</h2> <p>A tool for cleaning SVG Files - (yet partial) port of Scour to JavaScript.</p> <p>Visit the original <a href="http://codedread.com/scour/">Scour - an SVG scrubber, http://codedread.com/scour/</a></p> <p>Scour was created by Jeff Schiller.</p> <p>Please note that this is a partial port, which means it is not finsihed at all. For thoose who want to clean their SVG files and have them as clean as possible as I highly recommend to use the original Scour.py. (Please see the list of implemented and missing processing steps below.)</p> <h2>License</h2> <p>SVG Cleaner Copyright 2012 Michael Schieben</p> <p>Scour Copyright 2010 Jeff Schiller Copyright 2010 Louis Simard</p> <p>Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at</p> <p>http://www.apache.org/licenses/LICENSE-2.0</p> <p>Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.</p> <h2>About the port</h2> <p>I needed a library to work with <a href="http://github.com/preciousforever/SVG-Stacker">SVG-Stacker</a>, that could rename IDs and keep the references inside the SVG document structure intact. SVG-Stacker merges different svg files and needs to make sure that the ids from different files are unique in the merged version. If found that Scour implemented that feature.</p> <p>The goal of the port was to bring the power of Scour to the JavaScript world, make it available as commandline tool and usable as module for node.js.</p> <p>I tried to keep the ideas and way how Scour cleans SVG files. I translated the processing steps and copied most of the original comments from scour into the new source code, as they describe the original ideas best. I marked all of these orginial comments by putting 'Scour:' in the first line an used the markdown syntax for quotes (>). </p> <ul> <li>Missing processing steps are marked with an comment '@missing'.</li> <li>Changed processing steps are marked with an comment containern '@extended' or '@changed'</li> <li>Some functions and variable names are changed to (hopefully) be more descriptive.</li> </ul> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-2"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-2">&#182;</a> </div> <h2>Implemented</h2> <ul> <li>Removal of namespaced elements and attributes</li> <li>Removal of comments</li> <li>Repairation of styles</li> <li>Removal of unreferenced elements</li> <li>Removal of empty elements</li> <li>Removal of unused attributes</li> <li>Shortening of id attribute values</li> </ul> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-3"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-3">&#182;</a> </div> <h2>Missing</h2> <ul> <li>remove the xmlns: declarations now</li> <li>ensure namespace for SVG is declared</li> <li>check for redundant SVG namespace declaration</li> <li>convert colors to #RRGGBB format</li> <li>remove <metadata> if the user wants to</li> <li>flattend defs elements into just one defs element</li> <li>removeDuplicateGradientStops();</li> <li>remove gradients that are only referenced by one other gradient</li> <li>remove duplicate gradients</li> <li>createGroupsForCommonAttributes()</li> <li>move common attributes to parent group</li> <li>remove unused attributes from parent</li> <li>moveAttributesToParentGroup</li> <li>remove unnecessary closing point of polygons and scour points</li> <li>scour points of polyline</li> <li>clean path data</li> <li>scour lengths (including coordinates)</li> <li>reducePrecision</li> <li>removeDefaultAttributeValues</li> <li>optimizeTransforms</li> <li>convert rasters references to base64-encoded strings</li> <li>properly size the SVG document</li> </ul> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-4"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-4">&#182;</a> </div> <h2>Original Notes from Scour</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-5"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-5">&#182;</a> </div> <p>Scour:</p> <blockquote> <p>Notes:</p> <p>rubys' path-crunching ideas here: <a href="">http://intertwingly.net/code/svgtidy/spec.rb</a> (and implemented here: http://intertwingly.net/code/svgtidy/svgtidy.rb )</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-6"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-6">&#182;</a> </div> <blockquote> <p>Yet more ideas here: <a href="http://wiki.inkscape.org/wiki/index.php/Save_Cleaned_SVG">Inkscape Wiki</a></p> <ul> <li>Process Transformations <ul><li>Collapse all group based transformations</li></ul></li> </ul> </blockquote> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-7"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-7">&#182;</a> </div> <blockquote> <p>Even more ideas here: <a href="">http://esw.w3.org/topic/SvgTidy</a></p> <ul> <li>analysis of path elements to see if rect can be used instead? (must also need to look at rounded corners)</li> </ul> </blockquote> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-8"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-8">&#182;</a> </div> <blockquote> <p>Next Up:</p> <ul> <li>why are marker-start, -end not removed from the style attribute?</li> <li>why are only overflow style properties considered and not attributes?</li> <li>only remove unreferenced elements if they are not children of a referenced element</li> <li>add an option to remove ids if they match the Inkscape-style of IDs</li> <li>investigate point-reducing algorithms</li> <li>parse transform attribute</li> <li>if a <g> has only one element in it, collapse the <g> (ensure transform, etc are carried down)</li> </ul> </blockquote> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-9"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-9">&#182;</a> </div> <h2>Implementation</h2> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">_</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;underscore&#39;</span><span class="p">)</span> <span class="p">,</span> <span class="nx">fs</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;fs&#39;</span><span class="p">)</span> <span class="p">,</span> <span class="nx">cheerio</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;cheerio&#39;</span><span class="p">)</span> <span class="p">,</span> <span class="nx">CSSOM</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;cssom&#39;</span><span class="p">)</span> <span class="p">,</span> <span class="nx">$</span> <span class="p">;</span></pre></div> </td> </tr> <tr id="section-10"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-10">&#182;</a> </div> <p>Namespace Prefixes that should be removed</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">namespacePrefixes</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;dc&#39;</span><span class="p">,</span> <span class="s1">&#39;rdf&#39;</span><span class="p">,</span> <span class="s1">&#39;sodipodi&#39;</span><span class="p">,</span> <span class="s1">&#39;cc&#39;</span><span class="p">,</span> <span class="s1">&#39;inkscape&#39;</span><span class="p">];</span></pre></div> </td> </tr> <tr id="section-11"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-11">&#182;</a> </div> <hr /> <h2>Sanitize References</h2> </td> <td class="code"> <div class="highlight"><pre></pre></div> </td> </tr> <tr id="section-12"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-12">&#182;</a> </div> <p>Scour: Removes the unreferenced ID attributes.</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">removeUnreferencedIDs</span><span class="p">()</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">identifiedElements</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;[id]&#39;</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">referencedIDs</span> <span class="o">=</span> <span class="nx">findReferencedElements</span><span class="p">();</span> <span class="nx">_</span><span class="p">(</span><span class="nx">identifiedElements</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span><span class="err"> </span><span class="p">{</span> <span class="kd">var</span> <span class="nx">$node</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">$node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">_</span><span class="p">(</span><span class="nx">referencedIDs</span><span class="p">).</span><span class="nx">has</span><span class="p">(</span><span class="nx">id</span><span class="p">))</span> <span class="p">{</span> <span class="nx">$node</span><span class="p">.</span><span class="nx">removeAttr</span><span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">);</span> <span class="p">};</span> <span class="p">});</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-13"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-13">&#182;</a> </div> <p>Style-Properties and Element-Attributes that might contain an id, a reference to another object</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">var</span> <span class="nx">referencingProperties</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;fill&#39;</span><span class="p">,</span> <span class="s1">&#39;stroke&#39;</span><span class="p">,</span> <span class="s1">&#39;filter&#39;</span><span class="p">,</span> <span class="s1">&#39;clip-path&#39;</span><span class="p">,</span> <span class="s1">&#39;mask&#39;</span><span class="p">,</span> <span class="s1">&#39;marker-start&#39;</span><span class="p">,</span> <span class="s1">&#39;marker-end&#39;</span><span class="p">,</span> <span class="s1">&#39;marker-mid&#39;</span><span class="p">];</span> <span class="kd">var</span> <span class="nx">REFERENCE_TYPE</span> <span class="o">=</span> <span class="p">{</span> <span class="nx">STYLE_TAG</span><span class="o">:</span> <span class="mi">0</span><span class="p">,</span> <span class="nx">XLINK</span><span class="o">:</span> <span class="mi">1</span><span class="p">,</span> <span class="nx">STYLE_ATTRIBUTE</span><span class="o">:</span> <span class="mi">2</span><span class="p">,</span> <span class="nx">ATTRIBUTE</span><span class="o">:</span> <span class="mi">4</span> <span class="p">};</span> <span class="kd">function</span> <span class="nx">addReferencingElement</span><span class="p">(</span><span class="nx">ids</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">referenceType</span><span class="p">,</span> <span class="nx">node</span><span class="p">,</span> <span class="nx">additionalInfo</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">id</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/#/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">_</span><span class="p">(</span><span class="nx">ids</span><span class="p">).</span><span class="nx">has</span><span class="p">(</span><span class="nx">id</span><span class="p">))</span> <span class="p">{</span> <span class="nx">ids</span><span class="p">[</span><span class="nx">id</span><span class="p">]</span> <span class="o">=</span> <span class="p">[];</span> <span class="p">}</span> <span class="k">if</span><span class="p">(</span><span class="nx">_</span><span class="p">(</span><span class="nx">additionalInfo</span><span class="p">).</span><span class="nx">isUndefined</span><span class="p">())</span> <span class="p">{</span> <span class="nx">additionalInfo</span> <span class="o">=</span> <span class="p">[];</span> <span class="p">}</span> <span class="nx">ids</span><span class="p">[</span><span class="nx">id</span><span class="p">].</span><span class="nx">push</span><span class="p">([</span><span class="nx">referenceType</span><span class="p">,</span> <span class="nx">node</span><span class="p">,</span> <span class="nx">additionalInfo</span><span class="p">]);</span> <span class="k">return</span> <span class="nx">ids</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-14"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-14">&#182;</a> </div> <p>extracts #id out of CSS url('#id')</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">extractReferencedId</span><span class="p">(</span><span class="nx">value</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">v</span> <span class="o">=</span> <span class="nx">value</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/[\s]/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nx">v</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="s1">&#39;url&#39;</span><span class="p">)</span> <span class="o">!==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="kc">false</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="nx">value</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/[\s]/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">).</span><span class="nx">slice</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="o">-</span><span class="mi">1</span><span class="p">).</span><span class="nx">replace</span><span class="p">(</span><span class="sr">/[&quot;&#39;]/g</span><span class="p">,</span> <span class="s1">&#39;&#39;</span><span class="p">);</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-15"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-15">&#182;</a> </div> <p>replaced #fromid in CSS url('#fromid') to url('#toid')</p> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">replaceReferencedId</span><span class="p">(</span><span class="nx">value</span><span class="p">,</span> <span class="nx">idFrom</span><span class="p">,</span> <span class="nx">idTo</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">re</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">RegExp</span><span class="p">(</span><span class="s1">&#39;url\\([\&#39;&quot;]?#&#39;</span> <span class="o">+</span> <span class="nx">idFrom</span> <span class="o">+</span> <span class="s1">&#39;[\&#39;&quot;]?\\)&#39;</span><span class="p">,</span> <span class="s1">&#39;g&#39;</span><span class="p">);</span> <span class="k">return</span> <span class="nx">value</span><span class="p">.</span><span class="nx">replace</span><span class="p">(</span><span class="nx">re</span><span class="p">,</span> <span class="s2">&quot;url(#&quot;</span> <span class="o">+</span> <span class="nx">idTo</span> <span class="o">+</span> <span class="s2">&quot;)&quot;</span><span class="p">);</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-16"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-16">&#182;</a> </div> <p>Scour:</p> <blockquote> <p>Returns the number of times an ID is referenced as well as all elements that reference it. node is the node at which to start the search. The return value is a map which has the id as key and each value is an array where the first value is a count and the second value is a list of nodes that referenced it.</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">findReferencedElements</span><span class="p">()</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">ids</span> <span class="o">=</span> <span class="p">{};</span> <span class="nx">_</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="s1">&#39;*&#39;</span><span class="p">)).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">$node</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">name</span> <span class="o">==</span> <span class="s1">&#39;style&#39;</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">styles</span> <span class="o">=</span> <span class="nx">CSSOM</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">$node</span><span class="p">.</span><span class="nx">text</span><span class="p">());</span> <span class="nx">_</span><span class="p">(</span><span class="nx">styles</span><span class="p">.</span><span class="nx">cssRules</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">rule</span><span class="p">)</span> <span class="p">{</span> <span class="nx">_</span><span class="p">(</span><span class="nx">referencingProperties</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">referencingProperty</span><span class="p">)</span> <span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="nx">_</span><span class="p">(</span><span class="nx">rule</span><span class="p">.</span><span class="nx">style</span><span class="p">).</span><span class="nx">has</span><span class="p">(</span><span class="nx">referencingProperty</span><span class="p">))</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">extractReferencedId</span><span class="p">(</span><span class="nx">rule</span><span class="p">.</span><span class="nx">style</span><span class="p">[</span><span class="nx">referencingProperty</span><span class="p">]);</span> <span class="k">if</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span> <span class="nx">addReferencingElement</span><span class="p">(</span><span class="nx">ids</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">STYLE_TAG</span><span class="p">,</span> <span class="nx">node</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">});</span> <span class="p">});</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-17"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-17">&#182;</a> </div> <p>if xlink:href is set, then grab the id</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">href</span> <span class="o">=</span> <span class="nx">$node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;xlink:href&#39;</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nx">href</span><span class="p">)</span> <span class="p">{</span> <span class="nx">addReferencingElement</span><span class="p">(</span><span class="nx">ids</span><span class="p">,</span> <span class="nx">href</span><span class="p">,</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">XLINK</span><span class="p">,</span> <span class="nx">node</span><span class="p">);</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-18"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-18">&#182;</a> </div> <p>now get all style properties</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">styles</span> <span class="o">=</span> <span class="nx">parseStyles</span><span class="p">(</span><span class="nx">$node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;style&#39;</span><span class="p">));</span> <span class="nx">_</span><span class="p">(</span><span class="nx">referencingProperties</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">referencingProperty</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-19"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-19">&#182;</a> </div> <p>first check attributes</p> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">value</span> <span class="o">=</span> <span class="nx">$node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="nx">referencingProperty</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">_</span><span class="p">.</span><span class="nx">isUndefined</span><span class="p">(</span><span class="nx">value</span><span class="p">))</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">extractReferencedId</span><span class="p">(</span><span class="nx">value</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span> <span class="nx">addReferencingElement</span><span class="p">(</span><span class="nx">ids</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">ATTRIBUTE</span><span class="p">,</span> <span class="nx">node</span><span class="p">,</span> <span class="nx">referencingProperty</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-20"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-20">&#182;</a> </div> <p>then inline styles</p> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span><span class="p">(</span><span class="nx">_</span><span class="p">(</span><span class="nx">styles</span><span class="p">).</span><span class="nx">has</span><span class="p">(</span><span class="nx">referencingProperty</span><span class="p">))</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">extractReferencedId</span><span class="p">(</span><span class="nx">styles</span><span class="p">[</span><span class="nx">referencingProperty</span><span class="p">]);</span> <span class="k">if</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span> <span class="nx">addReferencingElement</span><span class="p">(</span><span class="nx">ids</span><span class="p">,</span> <span class="nx">id</span><span class="p">,</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">STYLE_ATTRIBUTE</span><span class="p">,</span> <span class="nx">node</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">});</span> <span class="p">});</span> <span class="k">return</span> <span class="nx">ids</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-21"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-21">&#182;</a> </div> <p>scour:</p> <blockquote> <p>Shortens ID names used in the document. ID names referenced the most often are assigned the shortest ID names. @missing scour: If the list unprotectedElements is provided, only IDs from this list will be shortened.</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">shortenIDs</span><span class="p">(</span><span class="nx">startNumber</span><span class="p">)</span><span class="err"> </span><span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="nx">_</span><span class="p">.</span><span class="nx">isUndefined</span><span class="p">(</span><span class="nx">startNumber</span><span class="p">))</span> <span class="p">{</span> <span class="nx">startNumber</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="p">}</span> <span class="kd">var</span> <span class="nx">$identifiedElements</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="s1">&#39;[id]&#39;</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">referencedIDs</span> <span class="o">=</span> <span class="nx">findReferencedElements</span><span class="p">();</span></pre></div> </td> </tr> <tr id="section-22"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-22">&#182;</a> </div> <p>scour:</p> <blockquote> <p>Make idList (list of idnames) sorted by reference count descending, so the highest reference count is first. First check that there's actually a defining element for the current ID name. (Cyn: I've seen documents with #id references but no element with that ID!)</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre> <span class="kd">var</span> <span class="nx">idList</span> <span class="o">=</span> <span class="nx">_</span><span class="p">(</span><span class="nx">_</span><span class="p">(</span><span class="nx">referencedIDs</span><span class="p">).</span><span class="nx">keys</span><span class="p">()).</span><span class="nx">filter</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="p">(</span><span class="nx">$identifiedElements</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;#&#39;</span> <span class="o">+</span> <span class="nx">id</span><span class="p">).</span><span class="nx">size</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">);</span> <span class="p">});</span> <span class="nx">idList</span> <span class="o">=</span> <span class="nx">_</span><span class="p">(</span><span class="nx">idList</span><span class="p">).</span><span class="nx">sortBy</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nx">referencedIDs</span><span class="p">[</span><span class="nx">id</span><span class="p">].</span><span class="nx">length</span><span class="p">;</span> <span class="p">}).</span><span class="nx">reverse</span><span class="p">();</span> <span class="nx">_</span><span class="p">(</span><span class="nx">idList</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">shortendID</span> <span class="o">=</span> <span class="nx">intToID</span><span class="p">(</span><span class="nx">startNumber</span><span class="o">++</span><span class="p">);</span></pre></div> </td> </tr> <tr id="section-23"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-23">&#182;</a> </div> <p>scour:</p> <blockquote> <p>First make sure that <em>this</em> element isn't already using the ID name we want to give it.</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span><span class="p">(</span><span class="nx">id</span> <span class="o">==</span> <span class="nx">shortendID</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-24"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-24">&#182;</a> </div> <p>scour:</p> <blockquote> <p>Then, skip ahead if the new ID is already in identifiedElement</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre> <span class="k">while</span><span class="p">(</span><span class="nx">$identifiedElements</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;#&#39;</span> <span class="o">+</span> <span class="nx">shortendID</span><span class="p">).</span><span class="nx">size</span><span class="p">()</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="nx">shortendID</span> <span class="o">=</span> <span class="nx">intToID</span><span class="p">(</span><span class="nx">startNumber</span><span class="o">++</span><span class="p">);</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-25"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-25">&#182;</a> </div> <p>scour:</p> <blockquote> <p>Then go rename it.</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">renameID</span><span class="p">(</span><span class="nx">id</span><span class="p">,</span> <span class="nx">shortendID</span><span class="p">,</span> <span class="nx">$identifiedElements</span><span class="p">,</span> <span class="nx">referencedIDs</span><span class="p">);</span> <span class="p">});</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-26"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-26">&#182;</a> </div> <p>scour:</p> <blockquote> <p>Returns the ID name for the given ID number, spreadsheet-style, i.e. from a to z, then from aa to az, ba to bz, etc., until zz.</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">intToID</span><span class="p">(</span><span class="nx">num</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">idName</span> <span class="o">=</span> <span class="s1">&#39;&#39;</span><span class="p">;</span> <span class="k">while</span> <span class="p">(</span><span class="nx">num</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span> <span class="nx">num</span><span class="o">--</span><span class="p">;</span> <span class="nx">idName</span> <span class="o">=</span> <span class="nb">String</span><span class="p">.</span><span class="nx">fromCharCode</span><span class="p">((</span><span class="nx">num</span> <span class="o">%</span> <span class="mi">26</span><span class="p">)</span> <span class="o">+</span> <span class="s1">&#39;a&#39;</span><span class="p">.</span><span class="nx">charCodeAt</span><span class="p">(</span><span class="mi">0</span><span class="p">))</span> <span class="o">+</span> <span class="nx">idName</span><span class="p">;</span> <span class="nx">num</span> <span class="o">=</span> <span class="nb">Math</span><span class="p">.</span><span class="nx">floor</span><span class="p">(</span><span class="nx">num</span> <span class="o">/</span> <span class="mi">26</span><span class="p">)</span> <span class="p">}</span> <span class="k">return</span> <span class="nx">idName</span><span class="p">;</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-27"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-27">&#182;</a> </div> <p>scour:</p> <blockquote> <p>Changes the ID name from idFrom to idTo, on the declaring element as well as all references in the document doc.</p> <p>Updates identifiedElements and referencedIDs. Does not handle the case where idTo is already the ID name of another element in doc.</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">renameID</span><span class="p">(</span><span class="nx">idFrom</span><span class="p">,</span> <span class="nx">idTo</span><span class="p">,</span> <span class="nx">$identifiedElements</span><span class="p">,</span> <span class="nx">referencedIDs</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">$definingNode</span> <span class="o">=</span> <span class="nx">$identifiedElements</span><span class="p">.</span><span class="nx">find</span><span class="p">(</span><span class="s1">&#39;#&#39;</span> <span class="o">+</span> <span class="nx">idFrom</span><span class="p">);</span> <span class="nx">$definingNode</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="nx">idTo</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">referringNodes</span> <span class="o">=</span> <span class="nx">referencedIDs</span><span class="p">[</span><span class="nx">idFrom</span><span class="p">];</span> <span class="nx">_</span><span class="p">(</span><span class="nx">referringNodes</span><span class="p">).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">referenceTypeNodeAndAdditionalInfos</span><span class="p">)</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">property</span> <span class="o">=</span> <span class="nx">referenceTypeNodeAndAdditionalInfos</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span> <span class="kd">var</span> <span class="nx">node</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">referenceTypeNodeAndAdditionalInfos</span><span class="p">[</span><span class="mi">1</span><span class="p">]);</span> <span class="k">switch</span><span class="p">(</span><span class="nx">property</span><span class="p">)</span> <span class="p">{</span> <span class="k">case</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">STYLE_TAG</span><span class="o">:</span> <span class="nx">node</span><span class="p">.</span><span class="nx">text</span><span class="p">(</span><span class="nx">replaceReferencedId</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">text</span><span class="p">(),</span> <span class="nx">idFrom</span><span class="p">,</span> <span class="nx">idTo</span><span class="p">));</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">XLINK</span><span class="o">:</span> <span class="nx">node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;xlink:href&#39;</span><span class="p">,</span> <span class="s1">&#39;#&#39;</span> <span class="o">+</span> <span class="nx">idTo</span><span class="p">);</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">STYLE_ATTRIBUTE</span><span class="o">:</span> <span class="nx">node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;style&#39;</span><span class="p">,</span> <span class="nx">replaceReferencedId</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;style&#39;</span><span class="p">),</span> <span class="nx">idFrom</span><span class="p">,</span> <span class="nx">idTo</span><span class="p">));</span> <span class="k">break</span><span class="p">;</span> <span class="k">case</span> <span class="nx">REFERENCE_TYPE</span><span class="p">.</span><span class="nx">ATTRIBUTE</span><span class="o">:</span> <span class="kd">var</span> <span class="nx">attributeName</span> <span class="o">=</span> <span class="nx">referenceTypeNodeAndAdditionalInfos</span><span class="p">[</span><span class="mi">2</span><span class="p">];</span> <span class="nx">node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="nx">attributeName</span><span class="p">,</span> <span class="nx">replaceReferencedId</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="nx">attributeName</span><span class="p">),</span> <span class="nx">idFrom</span><span class="p">,</span> <span class="nx">idTo</span><span class="p">));</span> <span class="k">break</span><span class="p">;</span> <span class="k">default</span><span class="o">:</span></pre></div> </td> </tr> <tr id="section-28"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-28">&#182;</a> </div> <p>unkonw reference_type</p> </td> <td class="code"> <div class="highlight"><pre> <span class="p">}</span> <span class="p">});</span> <span class="p">}</span></pre></div> </td> </tr> <tr id="section-29"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-29">&#182;</a> </div> <p>scour:</p> <blockquote> <p>removes all unreferenced elements except for <code>&lt;svg&gt;, &lt;font&gt;, &lt;metadata&gt;, &lt;title&gt;, and &lt;desc&gt;</code>. Also vacuums the defs of any non-referenced renderable elements.</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre><span class="kd">function</span> <span class="nx">removeUnreferencedElements</span><span class="p">()</span> <span class="p">{</span> <span class="kd">var</span> <span class="nx">referencedIDs</span> <span class="o">=</span> <span class="nx">findReferencedElements</span><span class="p">();</span> <span class="kd">var</span> <span class="nx">alwaysKeepTags</span> <span class="o">=</span> <span class="p">[</span><span class="s1">&#39;font&#39;</span><span class="p">,</span> <span class="s1">&#39;style&#39;</span><span class="p">,</span> <span class="s1">&#39;metadata&#39;</span><span class="p">,</span> <span class="s1">&#39;script&#39;</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="p">,</span> <span class="s1">&#39;desc&#39;</span><span class="p">];</span> <span class="kd">function</span> <span class="nx">removeUnreferencedElementsInTag</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span> <span class="nx">_</span><span class="p">(</span><span class="nx">$</span><span class="p">(</span><span class="nx">node</span><span class="p">).</span><span class="nx">children</span><span class="p">()).</span><span class="nx">each</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">node</span><span class="p">)</span> <span class="p">{</span> </pre></div> </td> </tr> <tr id="section-30"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-30">&#182;</a> </div> <p>scour:</p> <blockquote> <p>we only remove if it is not one of our tags we always keep (see above)</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre> <span class="k">if</span><span class="p">(</span><span class="nx">_</span><span class="p">(</span><span class="nx">alwaysKeepTags</span><span class="p">).</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">name</span><span class="p">)</span> <span class="o">!==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kd">var</span> <span class="nx">$node</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="nx">node</span><span class="p">);</span> <span class="kd">var</span> <span class="nx">id</span> <span class="o">=</span> <span class="nx">$node</span><span class="p">.</span><span class="nx">attr</span><span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">);</span> <span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">_</span><span class="p">(</span><span class="nx">referencedIDs</span><span class="p">).</span><span class="nx">has</span><span class="p">(</span><span class="nx">id</span><span class="p">))</span> <span class="p">{</span> <span class="k">if</span><span class="p">(</span><span class="nx">node</span><span class="p">.</span><span class="nx">name</span> <span class="o">==</span> <span class="s1">&#39;g&#39;</span><span class="p">)</span> <span class="p">{</span></pre></div> </td> </tr> <tr id="section-31"> <td class="docs"> <div class="pilwrap"> <a class="pilcrow" href="#section-31">&#182;</a> </div> <p>scour:</p> <blockquote> <p>we only inspect the children of a group in a defs if the group is not referenced anywhere else</p> </blockquote> </td> <td class="code"> <div class="highlight"><pre> <span class="nx">removeUnreferencedEl