source: frontend/node_modules/svgo/plugins/cleanupIDs.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 6.6 KB
Line 
1'use strict';
2
3exports.type = 'full';
4
5exports.active = true;
6
7exports.description = 'removes unused IDs and minifies used';
8
9exports.params = {
10 remove: true,
11 minify: true,
12 prefix: '',
13 preserve: [],
14 preservePrefixes: [],
15 force: false
16};
17
18var referencesProps = new Set(require('./_collections').referencesProps),
19 regReferencesUrl = /\burl\(("|')?#(.+?)\1\)/,
20 regReferencesHref = /^#(.+?)$/,
21 regReferencesBegin = /(\w+)\./,
22 styleOrScript = ['style', 'script'],
23 generateIDchars = [
24 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
25 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'
26 ],
27 maxIDindex = generateIDchars.length - 1;
28
29/**
30 * Remove unused and minify used IDs
31 * (only if there are no any <style> or <script>).
32 *
33 * @param {Object} item current iteration item
34 * @param {Object} params plugin params
35 *
36 * @author Kir Belevich
37 */
38exports.fn = function(data, params) {
39 var currentID,
40 currentIDstring,
41 IDs = new Map(),
42 referencesIDs = new Map(),
43 hasStyleOrScript = false,
44 preserveIDs = new Set(Array.isArray(params.preserve) ? params.preserve : params.preserve ? [params.preserve] : []),
45 preserveIDPrefixes = new Set(Array.isArray(params.preservePrefixes) ? params.preservePrefixes : (params.preservePrefixes ? [params.preservePrefixes] : [])),
46 idValuePrefix = '#',
47 idValuePostfix = '.';
48
49 /**
50 * Bananas!
51 *
52 * @param {Array} items input items
53 * @return {Array} output items
54 */
55 function monkeys(items) {
56 for (var i = 0; i < items.content.length && !hasStyleOrScript; i++) {
57 var item = items.content[i];
58
59 // quit if <style> or <script> present ('force' param prevents quitting)
60 if (!params.force) {
61 if (item.isElem(styleOrScript)) {
62 hasStyleOrScript = true;
63 continue;
64 }
65 // Don't remove IDs if the whole SVG consists only of defs.
66 if (item.isElem('defs') && item.parentNode.isElem('svg')) {
67 var hasDefsOnly = true;
68 for (var j = i + 1; j < items.content.length; j++) {
69 if (items.content[j].isElem()) {
70 hasDefsOnly = false;
71 break;
72 }
73 }
74 if (hasDefsOnly) {
75 break;
76 }
77 }
78 }
79 // …and don't remove any ID if yes
80 if (item.isElem()) {
81 item.eachAttr(function(attr) {
82 var key, match;
83
84 // save IDs
85 if (attr.name === 'id') {
86 key = attr.value;
87 if (IDs.has(key)) {
88 item.removeAttr('id'); // remove repeated id
89 } else {
90 IDs.set(key, item);
91 }
92 return;
93 }
94 // save references
95 if (referencesProps.has(attr.name) && (match = attr.value.match(regReferencesUrl))) {
96 key = match[2]; // url() reference
97 } else if (
98 attr.local === 'href' && (match = attr.value.match(regReferencesHref)) ||
99 attr.name === 'begin' && (match = attr.value.match(regReferencesBegin))
100 ) {
101 key = match[1]; // href reference
102 }
103 if (key) {
104 var ref = referencesIDs.get(key) || [];
105 ref.push(attr);
106 referencesIDs.set(key, ref);
107 }
108 });
109 }
110 // go deeper
111 if (item.content) {
112 monkeys(item);
113 }
114 }
115 return items;
116 }
117
118 data = monkeys(data);
119
120 if (hasStyleOrScript) {
121 return data;
122 }
123
124 const idPreserved = id => preserveIDs.has(id) || idMatchesPrefix(preserveIDPrefixes, id);
125
126 for (var ref of referencesIDs) {
127 var key = ref[0];
128
129 if (IDs.has(key)) {
130 // replace referenced IDs with the minified ones
131 if (params.minify && !idPreserved(key)) {
132 do {
133 currentIDstring = getIDstring(currentID = generateID(currentID), params);
134 } while (idPreserved(currentIDstring));
135
136 IDs.get(key).attr('id').value = currentIDstring;
137
138 for (var attr of ref[1]) {
139 attr.value = attr.value.includes(idValuePrefix) ?
140 attr.value.replace(idValuePrefix + key, idValuePrefix + currentIDstring) :
141 attr.value.replace(key + idValuePostfix, currentIDstring + idValuePostfix);
142 }
143 }
144 // don't remove referenced IDs
145 IDs.delete(key);
146 }
147 }
148 // remove non-referenced IDs attributes from elements
149 if (params.remove) {
150 for(var keyElem of IDs) {
151 if (!idPreserved(keyElem[0])) {
152 keyElem[1].removeAttr('id');
153 }
154 }
155 }
156 return data;
157};
158
159/**
160 * Check if an ID starts with any one of a list of strings.
161 *
162 * @param {Array} of prefix strings
163 * @param {String} current ID
164 * @return {Boolean} if currentID starts with one of the strings in prefixArray
165 */
166function idMatchesPrefix(prefixArray, currentID) {
167 if (!currentID) return false;
168
169 for (var prefix of prefixArray) if (currentID.startsWith(prefix)) return true;
170 return false;
171}
172
173/**
174 * Generate unique minimal ID.
175 *
176 * @param {Array} [currentID] current ID
177 * @return {Array} generated ID array
178 */
179function generateID(currentID) {
180 if (!currentID) return [0];
181
182 currentID[currentID.length - 1]++;
183
184 for(var i = currentID.length - 1; i > 0; i--) {
185 if (currentID[i] > maxIDindex) {
186 currentID[i] = 0;
187
188 if (currentID[i - 1] !== undefined) {
189 currentID[i - 1]++;
190 }
191 }
192 }
193 if (currentID[0] > maxIDindex) {
194 currentID[0] = 0;
195 currentID.unshift(0);
196 }
197 return currentID;
198}
199
200/**
201 * Get string from generated ID array.
202 *
203 * @param {Array} arr input ID array
204 * @return {String} output ID string
205 */
206function getIDstring(arr, params) {
207 var str = params.prefix;
208 return str + arr.map(i => generateIDchars[i]).join('');
209}
Note: See TracBrowser for help on using the repository browser.