1 | # hexo-util
|
2 |
|
3 | [![Build Status](https://github.com/hexojs/hexo-util/workflows/Tester/badge.svg?branch=master)](https://github.com/hexojs/hexo-util/actions?query=workflow%3ATester)
|
4 | [![NPM version](https://badge.fury.io/js/hexo-util.svg)](https://www.npmjs.com/package/hexo-util)
|
5 | [![Coverage Status](https://coveralls.io/repos/hexojs/hexo-util/badge.svg?branch=master&service=github)](https://coveralls.io/github/hexojs/hexo-util?branch=master)
|
6 |
|
7 | Utilities for [Hexo].
|
8 |
|
9 | ## Table of contents
|
10 |
|
11 | - [Installation](#installation)
|
12 | - [Usage](#usage)
|
13 | - [Cache](#cache)
|
14 | - [CacheStream](#cachestream)
|
15 | - [camelCaseKeys](#camelcasekeysobj-options)
|
16 | - [createSha1Hash](#createsha1hash)
|
17 | - [decodeURL](#decodeurlstr)
|
18 | - [deepMerge](#deepmergetarget-source)
|
19 | - [encodeURL](#encodeurlstr)
|
20 | - [escapeDiacritic](#escapediacriticstr)
|
21 | - [escapeHTML](#escapehtmlstr)
|
22 | - [escapeRegex](#escaperegexstr)
|
23 | - [full_url_for](#full_url_forpath)
|
24 | - [gravatar](#gravatarstr-options)
|
25 | - [hash](#hashstr)
|
26 | - [highlight](#highlightstr-options)
|
27 | - [htmlTag](#htmltagtag-attrs-text-escape)
|
28 | - [isExternalLink](#isexternallinkurl-sitehost-exclude)
|
29 | - [Pattern](#patternrule)
|
30 | - [Permalink](#permalinkrule-options)
|
31 | - [prettyUrls](#prettyurlsurl-options)
|
32 | - [prismHighlight](#prismhighlightstr-options)
|
33 | - [relative_url](#relative_urlfrom-to)
|
34 | - [slugize](#slugizestr-options)
|
35 | - [spawn](#spawncommand-args-options)
|
36 | - [stripHTML](#striphtmlstr)
|
37 | - [wordWrap](#wordwrapstr-options)
|
38 | - [tocObj](#tocobjstr-options)
|
39 | - [truncate](#truncatestr-options)
|
40 | - [unescapeHTML](#unescapehtmlstr)
|
41 | - [url_for](#url_forpath-option)
|
42 | - [bind(hexo)](#bindhexo)
|
43 |
|
44 | ## Installation
|
45 |
|
46 | ``` bash
|
47 | $ npm install hexo-util --save
|
48 | ```
|
49 |
|
50 | ## Usage
|
51 |
|
52 | ``` js
|
53 | var util = require('hexo-util');
|
54 | ```
|
55 |
|
56 | ### Cache()
|
57 |
|
58 | A simple plain object cache
|
59 |
|
60 | ``` js
|
61 | const cache = new Cache();
|
62 |
|
63 | // set(key, value)
|
64 | cache.set('foo', 'bar');
|
65 |
|
66 | // get(key) => value
|
67 | cache.get('foo');
|
68 | // 'bar'
|
69 |
|
70 | // has(key) => Boolean
|
71 | cache.has('foo');
|
72 | // true
|
73 | cache.has('bar');
|
74 | // false
|
75 |
|
76 | // apply(key. value)
|
77 | cache.apply('baz', () => 123);
|
78 | // 123
|
79 | cache.apply('baz', () => 456);
|
80 | // 123
|
81 | cache.apply('qux', 456);
|
82 | // 456
|
83 | cache.apply('qux', '789');
|
84 | // 456
|
85 |
|
86 | // size()
|
87 | cache.size();
|
88 | // 3
|
89 |
|
90 | // dump()
|
91 | cache.dump();
|
92 | /*
|
93 | {
|
94 | foo: 'bar',
|
95 | baz: 123,
|
96 | qux: 456
|
97 | }
|
98 | */
|
99 |
|
100 | // del(key)
|
101 | cache.del('baz');
|
102 | cache.has('baz');
|
103 | // false
|
104 |
|
105 | // flush()
|
106 | cache.flush();
|
107 | cache.has('foo');
|
108 | // false
|
109 | cache.size();
|
110 | // 0
|
111 | ```
|
112 |
|
113 | ### CacheStream()
|
114 |
|
115 | Caches contents piped to the stream.
|
116 |
|
117 | ``` js
|
118 | var stream = new CacheStream();
|
119 |
|
120 | fs.createReadStream('/path/to/file').pipe(stream);
|
121 |
|
122 | stream.on('finish', function(){
|
123 | // Read cache piped to the stream
|
124 | console.log(stream.getCache());
|
125 |
|
126 | // Destroy cache
|
127 | stream.destroy();
|
128 | });
|
129 | ```
|
130 |
|
131 | ### camelCaseKeys(obj, options)
|
132 |
|
133 | Convert object keys to camelCase. Original keys will be converted to getter/setter and sync to the camelCase keys.
|
134 |
|
135 | ``` js
|
136 | camelCaseKeys({
|
137 | foo_bar: 'test'
|
138 | });
|
139 | // { fooBar: 'test', foo_bar: 'test' }
|
140 | ```
|
141 |
|
142 | ### createSha1Hash()
|
143 | return SHA1 hash object.
|
144 | This is the same as calling `createHash('utf8')` in the node.js native module crypto.
|
145 | ``` js
|
146 | const sha1 = createSha1Hash();
|
147 | fs.createReadStream('/path/to/file')
|
148 | .pipe(sha1)
|
149 | .on('finish', () => {
|
150 | console.log(sha1.read());
|
151 | });
|
152 | ```
|
153 |
|
154 | ### decodeURL(str)
|
155 |
|
156 | Decode [encoded](https://en.wikipedia.org/wiki/Percent-encoding) URL or path. An alternative to the native [`decodeURI()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURI) function, with added ability to decode [punycoded](https://en.wikipedia.org/wiki/Punycode) domain.
|
157 |
|
158 | ``` js
|
159 | decodeURL('http://foo.com/b%C3%A1r')
|
160 | // http://foo.com/bár
|
161 |
|
162 | decodeURL('http://xn--br-mia.com/baz')
|
163 | // http://bár.com/baz
|
164 |
|
165 | decodeURL('/foo/b%C3%A1r/')
|
166 | // /foo/bár/
|
167 |
|
168 | /* Alternatively, Node 10+ offers native API to decode punycoded domain */
|
169 | const {format} = require('url')
|
170 | decodeURI(format(new URL('http://xn--br-mia.com.com/b%C3%A1r'), {unicode: true}))
|
171 | // http://bár.com/báz
|
172 | ```
|
173 |
|
174 | ### deepMerge(target, source)
|
175 |
|
176 | Merges the enumerable properties of two objects deeply. `target` and `source` remain untouched.
|
177 |
|
178 | ``` js
|
179 | // Merge deeply
|
180 | const obj1 = {a: {b: 1, c: 1, d: {e: 1, f: 1}}};
|
181 | const obj2 = {a: {b: 2, d: {f: 'f'} }};
|
182 |
|
183 | deepMerge(obj1, obj2);
|
184 | // {a: {b: 2, c: 1, d: {e: 1, f: 'f'} }}
|
185 | ```
|
186 |
|
187 | ``` js
|
188 | // Arrays will be combined in the same property, similar to lodash.merge
|
189 | const obj1 = { 'a': [{ 'b': 2 }, { 'd': 4 }] };
|
190 | const obj2 = { 'a': [{ 'c': 3 }, { 'e': 5 }] };
|
191 |
|
192 | deepMerge(obj1, obj2);
|
193 | // { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] };
|
194 | ```
|
195 |
|
196 | ### encodeURL(str)
|
197 |
|
198 | Encode URL or path into a [safe format](https://en.wikipedia.org/wiki/Percent-encoding).
|
199 |
|
200 | ``` js
|
201 | encodeURL('http://foo.com/bár')
|
202 | // http://foo.com/b%C3%A1r
|
203 |
|
204 | encodeURL('/foo/bár/')
|
205 | // /foo/b%C3%A1r/
|
206 | ```
|
207 |
|
208 | ### escapeDiacritic(str)
|
209 |
|
210 | Escapes diacritic characters in a string.
|
211 |
|
212 | ### escapeHTML(str)
|
213 |
|
214 | Escapes HTML entities in a string.
|
215 |
|
216 | ``` js
|
217 | escapeHTML('<p>Hello "world".</p>')
|
218 | // <p>Hello "world".</p>
|
219 |
|
220 | /* support escaped characters */
|
221 | escapeHTML('<foo>bar</foo>')
|
222 | // <foo>bar</foo>
|
223 | ```
|
224 |
|
225 | ### escapeRegex(str)
|
226 |
|
227 | Escapes special characters in a regular expression.
|
228 |
|
229 | ### full_url_for(path)
|
230 |
|
231 | Returns a url with the config.url prefixed. Output is [encoded](#encodeurlstr) automatically. Requires [`bind(hexo)`](#bindhexo).
|
232 |
|
233 | ``` yml
|
234 | _config.yml
|
235 | url: https://example.com/blog # example
|
236 | ```
|
237 |
|
238 | ``` js
|
239 | full_url_for('/a/path')
|
240 | // https://example.com/blog/a/path
|
241 | ```
|
242 |
|
243 | ### gravatar(str, [options])
|
244 |
|
245 | Returns the gravatar image url from an email.
|
246 |
|
247 | If you didn't specify the [options] parameter, the default options will apply. Otherwise, you can set it to a number which will then be passed on as the size parameter to Gravatar. Finally, if you set it to an object, it will be converted into a query string of parameters for Gravatar.
|
248 |
|
249 | Option | Description | Default
|
250 | --- | --- | ---
|
251 | `s` | Output image size | 80
|
252 | `d` | Default image |
|
253 | `f` | Force default |
|
254 | `r` | Rating |
|
255 |
|
256 | More info: [Gravatar](https://en.gravatar.com/site/implement/images/)
|
257 |
|
258 | ``` js
|
259 | gravatar('a@abc.com')
|
260 | // https://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787
|
261 | gravatar('a@abc.com', 40)
|
262 | // https://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787?s=40
|
263 | gravatar('a@abc.com' {s: 40, d: 'https://via.placeholder.com/150'})
|
264 | // https://www.gravatar.com/avatar/b9b00e66c6b8a70f88c73cb6bdb06787?s=40&d=https%3A%2F%2Fvia.placeholder.com%2F150
|
265 | ```
|
266 |
|
267 | ### hash(str)
|
268 |
|
269 | Generates SHA1 hash.
|
270 |
|
271 | ``` js
|
272 | hash('123456');
|
273 | // <Buffer 7c 4a 8d 09 ca 37 62 af 61 e5 95 20 94 3d c2 64 94 f8 94 1b>
|
274 | ```
|
275 |
|
276 | ### highlight(str, [options])
|
277 |
|
278 | Syntax highlighting for a code block.
|
279 |
|
280 | Option | Description | Default
|
281 | --- | --- | ---
|
282 | `gutter` | Whether to show line numbers | true
|
283 | `wrap` | Whether to wrap the code block in [`<table>`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table) | true
|
284 | `firstLine` | First line number | 1
|
285 | `hljs` | Whether to use the `hljs-*` prefix for CSS classes | false
|
286 | `lang` | Language |
|
287 | `caption` | Caption |
|
288 | `tab`| Replace tabs |
|
289 | `autoDetect` | Detect language automatically (warning: slow)<br>_Sublanguage highlight requires `autoDetect` to be enabled and `lang` to be unset_ | false
|
290 | `mark` | Line highlight specific line(s) |
|
291 | `languageAttr` | Output code language into `data-language` attr | false
|
292 |
|
293 | ### htmlTag(tag, attrs, text, escape)
|
294 |
|
295 | Creates a html tag.
|
296 |
|
297 | Option | Description | Default
|
298 | --- | --- | ---
|
299 | `tag` | Tag / element name |
|
300 | `attrs` | Attribute(s) and its value.<br>Value is always [escaped](#escapehtmlstr), URL is always [encoded](#encodeurlstr). |
|
301 | `text` | Text, the value is always escaped<br>_(except for `<style>` tag)_ |
|
302 | `escape` | Whether to escape the text | true
|
303 |
|
304 | ``` js
|
305 | htmlTag('img', {src: 'example.png'})
|
306 | // <img src="example.png">
|
307 |
|
308 | htmlTag('a', {href: 'http://hexo.io/'}, 'Hexo')
|
309 | // <a href="http://hexo.io/">Hexo</a>
|
310 |
|
311 | htmlTag('link', {href: 'http://foo.com/'}, '<a>bar</a>')
|
312 | // <a href="http://foo.com/"><bar></a>
|
313 |
|
314 | htmlTag('a', {href: 'http://foo.com/'}, '<b>bold</b>', false)
|
315 | // <a href="http://foo.com/"><b>bold</b></a>
|
316 |
|
317 | /* text value of <style> won't be escaped, url is still encoded */
|
318 | htmlTag('style', {}, 'p { content: "<"; background: url("bár.jpg"); }')
|
319 | // <style>p { content: "<"; background: url("b%C3%A1r.jpg"); }</style>
|
320 |
|
321 | /* support script tag with async/defer */
|
322 | htmlTag('script', {src: '/foo.js', async: true}, '')
|
323 | // <script src="/foo.js" async></script>
|
324 | ```
|
325 |
|
326 | ### isExternalLink(url, sitehost, [exclude])
|
327 |
|
328 | Option | Description | Default
|
329 | --- | --- | ---
|
330 | `url` | The input URL. |
|
331 | `sitehost` | The hostname / url of website. You can also pass `hexo.config.url`. |
|
332 | `exclude` | Exclude hostnames. Specific subdomain is required when applicable, including www. | `[]`
|
333 |
|
334 | Returns if a given url is external link relative to given `sitehost` and `[exclude]`.
|
335 |
|
336 | ``` js
|
337 | // 'sitehost' can be a domain or url
|
338 | isExternalLink('https://example.com', 'example.com');
|
339 | // false
|
340 | isExternalLink('https://example.com', 'https://example.com');
|
341 | // false
|
342 | isExternalLink('https://example.com', '//example.com/blog/');
|
343 | // false
|
344 | ```
|
345 |
|
346 | ``` js
|
347 | isExternalLink('/archives/foo.html', 'example.com');
|
348 | // false
|
349 | isExternalLink('https://foo.com/', 'example.com');
|
350 | // true
|
351 | ```
|
352 |
|
353 | ``` js
|
354 | isExternalLink('https://foo.com', 'example.com', ['foo.com', 'bar.com']);
|
355 | // false
|
356 | isExternalLink('https://bar.com', 'example.com', ['foo.com', 'bar.com']);
|
357 | // false
|
358 | isExternalLink('https://baz.com/', 'example.com', ['foo.com', 'bar.com']);
|
359 | // true
|
360 | ```
|
361 |
|
362 |
|
363 | ### Pattern(rule)
|
364 |
|
365 | Parses the string and tests if the string matches the rule. `rule` can be a string, a regular expression or a function.
|
366 |
|
367 | ``` js
|
368 | var pattern = new Pattern('posts/:id');
|
369 |
|
370 | pattern.match('posts/89');
|
371 | // {0: 'posts/89', 1: '89', id: '89'}
|
372 | ```
|
373 |
|
374 | ``` js
|
375 | var pattern = new Pattern('posts/*path');
|
376 |
|
377 | pattern.match('posts/2013/hello-world');
|
378 | // {0: 'posts/2013/hello-world', 1: '2013/hello-world', path: '2013/hello-world'}
|
379 | ```
|
380 |
|
381 | ### Permalink(rule, [options])
|
382 |
|
383 | Parses a permalink.
|
384 |
|
385 | Option | Description
|
386 | --- | ---
|
387 | `segments` | Customize the rule of a segment in the permalink
|
388 |
|
389 | ``` js
|
390 | var permalink = new Permalink(':year/:month/:day/:title', {
|
391 | segments: {
|
392 | year: /(\d{4})/,
|
393 | month: /(\d{2})/,
|
394 | day: /(\d{2})/
|
395 | }
|
396 | });
|
397 |
|
398 | permalink.parse('2014/01/31/test');
|
399 | // {year: '2014', month: '01', day: '31', title: 'test'}
|
400 |
|
401 | permalink.test('2014/01/31/test');
|
402 | // true
|
403 |
|
404 | permalink.stringify({year: '2014', month: '01', day: '31', title: 'test'})
|
405 | // 2014/01/31/test
|
406 | ```
|
407 |
|
408 | ### prettyUrls(url, [options])
|
409 |
|
410 | Rewrite urls to pretty URLs.
|
411 |
|
412 | Option | Description | Default
|
413 | --- | --- | ---
|
414 | `trailing_index` | `/about/index.html -> /about/` when `false` | `true`
|
415 | `trailing_html` | `/about.html -> /about` when `false` | `true`
|
416 |
|
417 | Note: `trailing_html` ignores any link with a trailing `index.html`. (will not be rewritten to `index`).
|
418 |
|
419 | ``` js
|
420 | prettyUrls('/foo/bar.html');
|
421 | // /foo/bar.html
|
422 | prettyUrls('/foo/bar/index.html');
|
423 | // /foo/bar/index.html
|
424 |
|
425 | prettyUrls('/foo/bar.html', { trailing_index: false });
|
426 | // /foo/bar.html
|
427 | prettyUrls('/foo/bar/index.html', { trailing_index: false });
|
428 | // /foo/bar/
|
429 |
|
430 | prettyUrls('/foo/bar.html', { trailing_html: false });
|
431 | // /foo/bar
|
432 | prettyUrls('/foo/bar/index.html', { trailing_html: false });
|
433 | // /foo/bar/index.html
|
434 |
|
435 | prettyUrls('/foo/bar.html', { trailing_index: false, trailing_html: false });
|
436 | // /foo/bar
|
437 | prettyUrls('/foo/bar/index.html', { trailing_index: false, trailing_html: false });
|
438 | // /foo/bar/
|
439 | ```
|
440 |
|
441 | ### prismHighlight(str, [options])
|
442 |
|
443 | Syntax highlighting for a code block using PrismJS.
|
444 |
|
445 | Option | Description | Default
|
446 | --- | --- | ---
|
447 | `lineNumber` | Whether to show line numbers | true
|
448 | `lang` | Language | `'none'`
|
449 | `tab`| Replace tabs |
|
450 | `isPreprocess` | Enable preprocess or not | true
|
451 | `mark` | Highlight specific line |
|
452 | `firstLine` | First line number |
|
453 | `caption` | Caption |
|
454 |
|
455 | When `isPreprocess` is enabled, `prismHighlight()` will return PrismJS processed HTML snippet. Otherwise `str` will only be escaped and `prismHighlight()` will return the HTML snippet that is suitable for `prism.js` working in the Browser.
|
456 |
|
457 | `mark` and `firstLine` options will have effect only when `isPreprocess` is disabled.
|
458 |
|
459 | ### relative_url(from, to)
|
460 |
|
461 | Returns the relative URL from `from` to `to`. Output is [encoded](#encodeurlstr) automatically. Requires [`bind(hexo)`](#bindhexo).
|
462 |
|
463 | ``` js
|
464 | relative_url('foo/bar/', 'css/style.css')
|
465 | // ../../css/style.css
|
466 | ```
|
467 |
|
468 | ### slugize(str, [options])
|
469 |
|
470 | Transforms a string into a clean URL-friendly string.
|
471 |
|
472 | Option | Description | Default
|
473 | --- | --- | ---
|
474 | `separator` | Separator | -
|
475 | `transform` | Transform the string into lower case (`1`) or upper case (`2`) |
|
476 |
|
477 | ``` js
|
478 | slugize('Hello World') = 'Hello-World'
|
479 | slugize('Hellô Wòrld') = 'Hello-World'
|
480 | slugize('Hello World', {separator: '_'}) = 'Hello_World'
|
481 | slugize('Hello World', {transform: 1}) = 'hello-world'
|
482 | slugize('Hello World', {transform: 2}) = 'HELLO-WORLD'
|
483 | ```
|
484 |
|
485 | ### spawn(command, [args], [options])
|
486 |
|
487 | Launches a new process with the given `command`. This method returns a promise.
|
488 |
|
489 | Option | Description | Default
|
490 | --- | --- | ---
|
491 | `cwd` | Current working directory of the child process |
|
492 | `env` | Environment key-value pairs |
|
493 | `stdio` | Child's stdio configuration | `pipe`
|
494 | `detached` | The child will be a process group leader |
|
495 | `uid` | Sets the user identity of the process |
|
496 | `gid` | Sets the group identity of the process |
|
497 | `verbose` | Display messages on the console | `false`
|
498 | `encoding` | Sets the encoding of the output string | `utf8`
|
499 |
|
500 | More info: [`child_process.spawn()`](https://nodejs.org/api/child_process.html#child_process_child_process_spawn_command_args_options)
|
501 |
|
502 | ``` js
|
503 | spawn('cat', 'test.txt').then((content) => {
|
504 | console.log(content);
|
505 | });
|
506 |
|
507 | // $ cd "/target/folder"
|
508 | // $ cat "foo.txt" "bar.txt"
|
509 | spawn('cat', ['foo.txt', 'bar.txt'], { cwd: '/target/folder' }).then((content) => {
|
510 | console.log(content);
|
511 | });
|
512 | ```
|
513 |
|
514 | ### stripHTML(str)
|
515 |
|
516 | Removes HTML tags in a string.
|
517 |
|
518 | ### stripIndent(str)
|
519 |
|
520 | Strip leading whitespace from each line in a string. The line with the least number of leading whitespace, ignoring empty lines, determines the number to remove. Useful for removing redundant indentation.
|
521 |
|
522 | ### wordWrap(str, [options])
|
523 |
|
524 | Wraps the string no longer than line width. This method breaks on the first whitespace character that does not exceed line width.
|
525 |
|
526 | Option | Description | Default
|
527 | --- | --- | ---
|
528 | `width` | Line width | 80
|
529 |
|
530 | ``` js
|
531 | wordWrap('Once upon a time')
|
532 | // Once upon a time
|
533 |
|
534 | wordWrap('Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding a successor to the throne turned out to be more trouble than anyone could have imagined...')
|
535 | // Once upon a time, in a kingdom called Far Far Away, a king fell ill, and finding\na successor to the throne turned out to be more trouble than anyone could have\nimagined...
|
536 |
|
537 | wordWrap('Once upon a time', {width: 8})
|
538 | // Once\nupon a\ntime
|
539 |
|
540 | wordWrap('Once upon a time', {width: 1})
|
541 | // Once\nupon\na\ntime
|
542 | ```
|
543 |
|
544 | ### tocObj(str, [options])
|
545 |
|
546 | Generate a table of contents in JSON format based on the given html string. Headings with attribute `data-toc-unnumbered="true"` will be marked as unnumbered.
|
547 |
|
548 | Option | Description | Default
|
549 | --- | --- | ---
|
550 | `min_depth` | The minimum level of TOC | 1
|
551 | `max_depth` | The maximum level of TOC | 6
|
552 |
|
553 |
|
554 | ``` js
|
555 | const html = [
|
556 | '<h1 id="title_1">Title 1</h1>',
|
557 | '<div id="title_1_1"><h2>Title 1.1</h2></div>',
|
558 | '<h3 id="title_1_1_1">Title 1.1.1</h3>',
|
559 | '<h2 id="title_1_2">Title 1.2</h2>',
|
560 | '<h2 id="title_1_3">Title 1.3</h2>',
|
561 | '<h3 id="title_1_3_1">Title 1.3.1</h3>',
|
562 | '<h1 id="title_2">Title 2</h1>',
|
563 | '<h2 id="title_2_1">Title 2.1</h2>'
|
564 | ].join('\n');
|
565 |
|
566 | tocObj(html);
|
567 | /*
|
568 | [
|
569 | { text: 'Title 1', id: 'title_1', level: 1 },
|
570 | { text: 'Title 1.1', id: 'title_1_1', level: 2 },
|
571 | { text: 'Title 1.1.1', id: 'title_1_1_1', level: 3 },
|
572 | { text: 'Title 1.2', id: 'title_1_2', level: 2 },
|
573 | { text: 'Title 1.3', id: 'title_1_3', level: 2 },
|
574 | { text: 'Title 1.3.1', id: 'title_1_3_1', level: 3 },
|
575 | { text: 'Title 2', id: 'title_2', level: 1 },
|
576 | { text: 'Title 2.1', id: 'title_2_1', level: 2 },
|
577 | ]
|
578 | */
|
579 |
|
580 | tocObj(html, { min_depth: 2 });
|
581 | /*
|
582 | [
|
583 | { text: 'Title 1.1', id: 'title_1_1', level: 2 },
|
584 | { text: 'Title 1.1.1', id: 'title_1_1_1', level: 3 },
|
585 | { text: 'Title 1.2', id: 'title_1_2', level: 2 },
|
586 | { text: 'Title 1.3', id: 'title_1_3', level: 2 },
|
587 | { text: 'Title 1.3.1', id: 'title_1_3_1', level: 3 },
|
588 | { text: 'Title 2.1', id: 'title_2_1', level: 2 },
|
589 | ]
|
590 | */
|
591 |
|
592 | tocObj(html, { max_depth: 2 });
|
593 | /*
|
594 | [
|
595 | { text: 'Title 1', id: 'title_1', level: 1 },
|
596 | { text: 'Title 1.1', id: 'title_1_1', level: 2 },
|
597 | { text: 'Title 1.2', id: 'title_1_2', level: 2 },
|
598 | { text: 'Title 1.3', id: 'title_1_3', level: 2 },
|
599 | { text: 'Title 2', id: 'title_2', level: 1 },
|
600 | { text: 'Title 2.1', id: 'title_2_1', level: 2 },
|
601 | ]
|
602 | */
|
603 |
|
604 | tocObj('<h1 id="reference" data-toc-unnumbered="true">Reference</h1>')
|
605 | /*
|
606 | [
|
607 | { text: 'Reference', id: 'reference', level: 1, unnumbered: true }
|
608 | ]
|
609 | */
|
610 | ```
|
611 |
|
612 | ### truncate(str, [options])
|
613 |
|
614 | Truncates a given text after a given `length` if text is longer than `length`. The last characters will be replaced with the `omission` option for a total length not exceeding `length`.
|
615 |
|
616 | Option | Description | Default
|
617 | --- | --- | ---
|
618 | `length` | Max length of the string | 30
|
619 | `omission` | Omission text | ...
|
620 | `separator` | truncate text at a natural break |
|
621 |
|
622 | ``` js
|
623 | truncate('Once upon a time in a world far far away')
|
624 | // "Once upon a time in a world..."
|
625 |
|
626 | truncate('Once upon a time in a world far far away', {length: 17})
|
627 | // "Once upon a ti..."
|
628 |
|
629 | truncate('Once upon a time in a world far far away', {length: 17, separator: ' '})
|
630 | // "Once upon a..."
|
631 |
|
632 | truncate('And they found that many people were sleeping better.', {length: 25, omission: '... (continued)'})
|
633 | // "And they f... (continued)"
|
634 | ```
|
635 |
|
636 | ### unescapeHTML(str)
|
637 |
|
638 | Unescapes HTML entities in a string.
|
639 |
|
640 | ``` js
|
641 | unescapeHTML('<p>Hello "world".</p>')
|
642 | // <p>Hello "world".</p>
|
643 | ```
|
644 |
|
645 | ### url_for(path, [option])
|
646 |
|
647 | Returns a url with the root path prefixed. Output is [encoded](#encodeurlstr) automatically. Requires [`bind(hexo)`](#bindhexo).
|
648 |
|
649 | Option | Description | Default
|
650 | --- | --- | ---
|
651 | `relative` | Output relative link | Value of `config.relative_link`
|
652 |
|
653 | ``` yml
|
654 | _config.yml
|
655 | root: /blog/ # example
|
656 | ```
|
657 |
|
658 | ``` js
|
659 | url_for('/a/path')
|
660 | // /blog/a/path
|
661 | ```
|
662 |
|
663 | Relative link, follows `relative_link` option by default
|
664 | e.g. post/page path is '/foo/bar/index.html'
|
665 |
|
666 | ``` yml
|
667 | _config.yml
|
668 | relative_link: true
|
669 | ```
|
670 |
|
671 | ``` js
|
672 | url_for('/css/style.css')
|
673 | // ../../css/style.css
|
674 |
|
675 | /* Override option
|
676 | * you could also disable it to output a non-relative link,
|
677 | * even when `relative_link` is enabled and vice versa.
|
678 | */
|
679 | url_for('/css/style.css', {relative: false})
|
680 | // /css/style.css
|
681 | ```
|
682 |
|
683 | ## bind(hexo)
|
684 |
|
685 | Following utilities require `bind(hexo)` / `bind(this)` / `call(hexo, input)` / `call(this, input)` to parse the user config when initializing:
|
686 | - [`full_url_for()`](#full_url_forpath)
|
687 | - [`url_for()`](#url_forpath)
|
688 | - [`relative_url()`](#relative_urlfrom-to)
|
689 |
|
690 | Below examples demonstrate different approaches to creating a [helper](https://hexo.io/api/helper) (each example is separated by `/******/`),
|
691 |
|
692 | ``` js
|
693 | // Single function
|
694 | const url_for = require('hexo-util').url_for.bind(hexo);
|
695 |
|
696 | hexo.extend.helper.register('test_url', (str) => {
|
697 | return url_for(str);
|
698 | })
|
699 |
|
700 |
|
701 | /******/
|
702 | // Multiple functions
|
703 | const url_for = require('hexo-util').url_for.bind(hexo)
|
704 |
|
705 | function testurlHelper(str) {
|
706 | return url_for(str);
|
707 | }
|
708 |
|
709 | hexo.extend.helper.register('test_url', testurlHelper);
|
710 |
|
711 |
|
712 | /******/
|
713 | // Functions separated into different files.
|
714 | // test_url.js
|
715 | module.exports = function(str) {
|
716 | const url_for = require('hexo-util').url_for.bind(this);
|
717 | return url_for(str);
|
718 | }
|
719 |
|
720 | // index.js
|
721 | hexo.extend.helper.register('test_url', require('./test_url'));
|
722 |
|
723 |
|
724 | /******/
|
725 | // Function.call() approach also works
|
726 | const {url_for} = require('hexo-util');
|
727 | module.exports = function(str) {
|
728 | return url_for.call(this, str);
|
729 | }
|
730 |
|
731 | hexo.extend.helper.register('test_url', require('./test_url'));
|
732 |
|
733 |
|
734 | /******/
|
735 | // Separating functions into individual files
|
736 | // Each file has multiple functions
|
737 | // test_url.js
|
738 | function testurlHelper(str) {
|
739 | const url_for = require('hexo-util').url_for.bind(this);
|
740 | return url_for(str);
|
741 | }
|
742 |
|
743 | module.exports = {
|
744 | testurlHelper: testurlHelper
|
745 | }
|
746 |
|
747 | // index.js
|
748 | hexo.extend.helper.register('test_url', require('./test_url').testurlHelper);
|
749 | ```
|
750 |
|
751 | ## License
|
752 |
|
753 | MIT
|
754 |
|
755 | [Hexo]: http://hexo.io/
|