UNPKG

5.64 kBJavaScriptView Raw
1(function () {
2
3 if (typeof Prism === 'undefined') {
4 return;
5 }
6
7 var assign = Object.assign || function (obj1, obj2) {
8 for (var name in obj2) {
9 if (obj2.hasOwnProperty(name)) {
10 obj1[name] = obj2[name];
11 }
12 }
13 return obj1;
14 };
15
16 function NormalizeWhitespace(defaults) {
17 this.defaults = assign({}, defaults);
18 }
19
20 function toCamelCase(value) {
21 return value.replace(/-(\w)/g, function (match, firstChar) {
22 return firstChar.toUpperCase();
23 });
24 }
25
26 function tabLen(str) {
27 var res = 0;
28 for (var i = 0; i < str.length; ++i) {
29 if (str.charCodeAt(i) == '\t'.charCodeAt(0)) {
30 res += 3;
31 }
32 }
33 return str.length + res;
34 }
35
36 var settingsConfig = {
37 'remove-trailing': 'boolean',
38 'remove-indent': 'boolean',
39 'left-trim': 'boolean',
40 'right-trim': 'boolean',
41 'break-lines': 'number',
42 'indent': 'number',
43 'remove-initial-line-feed': 'boolean',
44 'tabs-to-spaces': 'number',
45 'spaces-to-tabs': 'number',
46 };
47
48 NormalizeWhitespace.prototype = {
49 setDefaults: function (defaults) {
50 this.defaults = assign(this.defaults, defaults);
51 },
52 normalize: function (input, settings) {
53 settings = assign(this.defaults, settings);
54
55 for (var name in settings) {
56 var methodName = toCamelCase(name);
57 if (name !== 'normalize' && methodName !== 'setDefaults' &&
58 settings[name] && this[methodName]) {
59 input = this[methodName].call(this, input, settings[name]);
60 }
61 }
62
63 return input;
64 },
65
66 /*
67 * Normalization methods
68 */
69 leftTrim: function (input) {
70 return input.replace(/^\s+/, '');
71 },
72 rightTrim: function (input) {
73 return input.replace(/\s+$/, '');
74 },
75 tabsToSpaces: function (input, spaces) {
76 spaces = spaces|0 || 4;
77 return input.replace(/\t/g, new Array(++spaces).join(' '));
78 },
79 spacesToTabs: function (input, spaces) {
80 spaces = spaces|0 || 4;
81 return input.replace(RegExp(' {' + spaces + '}', 'g'), '\t');
82 },
83 removeTrailing: function (input) {
84 return input.replace(/\s*?$/gm, '');
85 },
86 // Support for deprecated plugin remove-initial-line-feed
87 removeInitialLineFeed: function (input) {
88 return input.replace(/^(?:\r?\n|\r)/, '');
89 },
90 removeIndent: function (input) {
91 var indents = input.match(/^[^\S\n\r]*(?=\S)/gm);
92
93 if (!indents || !indents[0].length) {
94 return input;
95 }
96
97 indents.sort(function (a, b) { return a.length - b.length; });
98
99 if (!indents[0].length) {
100 return input;
101 }
102
103 return input.replace(RegExp('^' + indents[0], 'gm'), '');
104 },
105 indent: function (input, tabs) {
106 return input.replace(/^[^\S\n\r]*(?=\S)/gm, new Array(++tabs).join('\t') + '$&');
107 },
108 breakLines: function (input, characters) {
109 characters = (characters === true) ? 80 : characters|0 || 80;
110
111 var lines = input.split('\n');
112 for (var i = 0; i < lines.length; ++i) {
113 if (tabLen(lines[i]) <= characters) {
114 continue;
115 }
116
117 var line = lines[i].split(/(\s+)/g);
118 var len = 0;
119
120 for (var j = 0; j < line.length; ++j) {
121 var tl = tabLen(line[j]);
122 len += tl;
123 if (len > characters) {
124 line[j] = '\n' + line[j];
125 len = tl;
126 }
127 }
128 lines[i] = line.join('');
129 }
130 return lines.join('\n');
131 }
132 };
133
134 // Support node modules
135 if (typeof module !== 'undefined' && module.exports) {
136 module.exports = NormalizeWhitespace;
137 }
138
139 Prism.plugins.NormalizeWhitespace = new NormalizeWhitespace({
140 'remove-trailing': true,
141 'remove-indent': true,
142 'left-trim': true,
143 'right-trim': true,
144 /*'break-lines': 80,
145 'indent': 2,
146 'remove-initial-line-feed': false,
147 'tabs-to-spaces': 4,
148 'spaces-to-tabs': 4*/
149 });
150
151 Prism.hooks.add('before-sanity-check', function (env) {
152 var Normalizer = Prism.plugins.NormalizeWhitespace;
153
154 // Check settings
155 if (env.settings && env.settings['whitespace-normalization'] === false) {
156 return;
157 }
158
159 // Check classes
160 if (!Prism.util.isActive(env.element, 'whitespace-normalization', true)) {
161 return;
162 }
163
164 // Simple mode if there is no env.element
165 if ((!env.element || !env.element.parentNode) && env.code) {
166 env.code = Normalizer.normalize(env.code, env.settings);
167 return;
168 }
169
170 // Normal mode
171 var pre = env.element.parentNode;
172 if (!env.code || !pre || pre.nodeName.toLowerCase() !== 'pre') {
173 return;
174 }
175
176 if (env.settings == null) { env.settings = {}; }
177
178 // Read settings from 'data-' attributes
179 for (var key in settingsConfig) {
180 if (Object.hasOwnProperty.call(settingsConfig, key)) {
181 var settingType = settingsConfig[key];
182 if (pre.hasAttribute('data-' + key)) {
183 try {
184 var value = JSON.parse(pre.getAttribute('data-' + key) || 'true');
185 if (typeof value === settingType) {
186 env.settings[key] = value;
187 }
188 } catch (_error) {
189 // ignore error
190 }
191 }
192 }
193 }
194
195 var children = pre.childNodes;
196 var before = '';
197 var after = '';
198 var codeFound = false;
199
200 // Move surrounding whitespace from the <pre> tag into the <code> tag
201 for (var i = 0; i < children.length; ++i) {
202 var node = children[i];
203
204 if (node == env.element) {
205 codeFound = true;
206 } else if (node.nodeName === '#text') {
207 if (codeFound) {
208 after += node.nodeValue;
209 } else {
210 before += node.nodeValue;
211 }
212
213 pre.removeChild(node);
214 --i;
215 }
216 }
217
218 if (!env.element.children.length || !Prism.plugins.KeepMarkup) {
219 env.code = before + env.code + after;
220 env.code = Normalizer.normalize(env.code, env.settings);
221 } else {
222 // Preserve markup for keep-markup plugin
223 var html = before + env.element.innerHTML + after;
224 env.element.innerHTML = Normalizer.normalize(html, env.settings);
225 env.code = env.element.textContent;
226 }
227 });
228
229}());