Butterfly Theme HTML Generation#
Overview#
Butterfly's sidebar widgets and inline HTML elements are generated by JavaScript helper scripts registered with Hexo via hexo.extend.helper.register. These helpers, located in scripts/helpers/, return raw HTML strings that Pug layout templates then interpolate directly.
Two primary construction patterns appear across the helpers:
.map().join('')β for arrays of sibling elements (list items, tag links)- Incremental
result +=concatenation β for conditional or hierarchical structures (nested category trees, related-post cards)
The central engineering concern in both patterns is whitespace control: template literals preserve all indentation and newlines, and stray whitespace between inline HTML elements (<a>, <span>, <img>) renders as a visible space character in browsers.
Key Source Files#
| File | Widget / Purpose |
|---|---|
scripts/helpers/aside_archives.js | Archives sidebar card |
scripts/helpers/aside_categories.js | Categories sidebar card |
scripts/helpers/related_post.js | Related posts sidebar card |
scripts/helpers/page.js | cloudTags tag cloud + injectHtml utility |
HTML Generation Patterns#
.map().join('') β Sibling List Elements#
The preferred pattern for rendering an array of peer elements. By passing an empty string to .join(), no separator (including no whitespace) is inserted between items.
- Archives widget β
aside_archives.jslines 89β102: maps each archive period to a<li>string, then calls.join('')before embedding the result in a<ul>template literal. - Tag cloud β
page.jslines 68β81: maps each tag to an<a>element with dynamically computed font-size and color styles, then joins with''. This is especially important for inline<a>elements, where any whitespace between tags would appear as a visible gap in the rendered cloud.
Incremental result += β Hierarchical / Conditional HTML#
Used when element inclusion is conditional or the structure is recursive.
- Categories widget β
aside_categories.jslines 45β83: the recursivehierarchicalListfunction appends<li>,<a>,<span>, and optionally<ul>child lists viaresult +=. Because each append is an explicit string concatenation with no separator, no whitespace gaps are introduced. - Related posts widget β
related_post.jslines 59β91: a loop appends post card HTML (cover image or styled placeholder, title link, optional description) withresult +=for each related post.
Template Literal Blocks β Widget Shells#
Multi-line template literals are used for structural wrapper HTML (headers, container <div>s, <ul> wrappers). Because these wrap block-level elements, indentation whitespace in the literal is harmless.
- Archives header + list shell β
aside_archives.jslines 71β104: separate template literals for theitem-headlineheader block and the<ul class="card-archive-list">wrapper, which embed the.join('')-produced list string. - Categories return β
aside_categories.jslines 92β99: the finalreturnstatement is a multi-line template literal with${list.result}(the recursively-built category items) and${moreButton}interpolated inline.
Whitespace Handling Rules#
| Situation | Risk | Mitigation |
|---|---|---|
Inline elements (<a>, <span>) joined from an array | Newline/indent between items β visible gap | .map(...).join('') |
Inline elements built with result += | None β no separator is inserted between += calls | result += pattern inherently whitespace-safe |
| Block elements inside a template literal | None β browsers collapse whitespace between block elements | Multi-line template literal is fine |
| HTML fragment arrays passed to templates | Gaps if naively concatenated | injectHtml joins with .join('') |
Rule of thumb: any time a map() over data produces sibling HTML elements, terminate with .join(''), not .join('\n') or the default .join(',').
injectHtml Utility#
page.js lines 92β94 registers a minimal injectHtml helper:
hexo.extend.helper.register('injectHtml', data => {
return data ? data.join('') : ''
})
This is the canonical Butterfly mechanism for injecting arbitrary user-configured HTML fragments (e.g. <head> injections, custom scripts). It follows the same .join('') discipline to prevent whitespace artifacts between consecutive fragments.