1 | var escape = require('escape-html')
|
2 | var group = require('commonform-group-series')
|
3 | var hash = require('commonform-hash')
|
4 | var predicate = require('commonform-predicate')
|
5 |
|
6 | function renderParagraph (paragraph, offset, path, blanks, html5) {
|
7 | return (
|
8 | '<p>' +
|
9 | paragraph.content
|
10 | .map(function (element, index) {
|
11 | if (predicate.text(element)) {
|
12 | return escape(element)
|
13 | } else if (predicate.use(element)) {
|
14 | return (
|
15 | '<span class="term">' +
|
16 | escape(element.use) +
|
17 | '</span>'
|
18 | )
|
19 | } else if (predicate.definition(element)) {
|
20 | return (
|
21 | (html5 ? '<dfn>' : '<span class="definition">') +
|
22 | escape(element.definition) +
|
23 | (html5 ? '</dfn>' : '</span>')
|
24 | )
|
25 | } else if (predicate.blank(element)) {
|
26 | var elementPath = path.concat('content', offset + index)
|
27 | var value = matchingValue(elementPath, blanks)
|
28 | return (
|
29 | '<span class="blank">' +
|
30 | (value ? escape(value) : escape('[•]')) +
|
31 | '</span>'
|
32 | )
|
33 | } else if (predicate.reference(element)) {
|
34 | return (
|
35 | '<span class="reference">' +
|
36 | escape(element.reference) +
|
37 | '</span>'
|
38 | )
|
39 | }
|
40 | })
|
41 | .join('') +
|
42 | '</p>'
|
43 | )
|
44 | }
|
45 |
|
46 | function matchingValue (path, blanks) {
|
47 | var length = blanks.length
|
48 | for (var index = 0; index < length; index++) {
|
49 | var blank = blanks[index]
|
50 | if (equal(blank.blank, path)) {
|
51 | return blank.value
|
52 | }
|
53 | }
|
54 | }
|
55 |
|
56 | function heading (depth, text) {
|
57 | if (depth <= 6) {
|
58 | return (
|
59 | '<h' + depth + '>' +
|
60 | escape(text) +
|
61 | '</h' + depth + '>'
|
62 | )
|
63 | } else {
|
64 | return (
|
65 | '<span class="h' + depth + '">' +
|
66 | escape(text) +
|
67 | '</span>'
|
68 | )
|
69 | }
|
70 | }
|
71 |
|
72 | function renderSeries (
|
73 | depth, offset, path, series, blanks, html5, lists
|
74 | ) {
|
75 | var simple = lists && !series.content.some(containsAHeading)
|
76 | if (simple) {
|
77 | return (
|
78 | '<ol>' +
|
79 | series.content
|
80 | .map(function (child, index) {
|
81 | return (
|
82 | (
|
83 | child.form.conspicuous
|
84 | ? '<li class="conspicuous">'
|
85 | : '<li>'
|
86 | ) +
|
87 | renderForm(
|
88 | depth,
|
89 | path.concat('content', offset + index, 'form'),
|
90 | child.form,
|
91 | blanks,
|
92 | html5,
|
93 | lists
|
94 | ) +
|
95 | '</li>'
|
96 | )
|
97 | })
|
98 | .join('') +
|
99 | '</ol>'
|
100 | )
|
101 | } else {
|
102 | return series.content
|
103 | .map(function (child, index) {
|
104 | return (
|
105 | (
|
106 | html5
|
107 | ? child.form.conspicuous
|
108 | ? '<section class="conspicuous">'
|
109 | : '<section>'
|
110 | : child.form.conspicuous
|
111 | ? '<div class="section conspicuous">'
|
112 | : '<div class="section">'
|
113 | ) +
|
114 | ('heading' in child ? heading(depth, child.heading) : '') +
|
115 | renderForm(
|
116 | depth,
|
117 | path.concat('content', offset + index, 'form'),
|
118 | child.form,
|
119 | blanks,
|
120 | html5,
|
121 | lists
|
122 | ) +
|
123 | (html5 ? '</section>' : '</div>')
|
124 | )
|
125 | })
|
126 | .join('')
|
127 | }
|
128 | }
|
129 |
|
130 | function renderForm (depth, path, form, blanks, html5, lists) {
|
131 | var offset = 0
|
132 | return group(form)
|
133 | .map(function (group) {
|
134 | var returned = group.type === 'series'
|
135 | ? renderSeries(
|
136 | depth + 1, offset, path, group, blanks, html5, lists
|
137 | )
|
138 | : renderParagraph(group, offset, path, blanks, html5)
|
139 | offset += group.content.length
|
140 | return returned
|
141 | })
|
142 | .join('')
|
143 | }
|
144 |
|
145 | module.exports = function commonformHTML (form, blanks, options) {
|
146 | blanks = blanks || []
|
147 | options = options || {}
|
148 | var html5 = 'html5' in options && options.html5 === true
|
149 | var lists = 'lists' in options && options.lists === true
|
150 | var title = 'title' in options ? options.title : false
|
151 | var edition = 'edition' in options ? options.edition : false
|
152 | return (
|
153 | (
|
154 | html5
|
155 | ? form.conspicuous
|
156 | ? '<article class="conspicuous">'
|
157 | : '<article>'
|
158 | : form.conspicuous
|
159 | ? '<div class="article conspicuous">'
|
160 | : '<div class="article">'
|
161 | ) +
|
162 | (title ? ('<h1>' + escape(title) + '</h1>') : '') +
|
163 | (edition ? ('<p class="edition">' + escape(edition) + '</p>') : '') +
|
164 | (
|
165 | options.hash
|
166 | ? ('<p class="hash"><code>' + hash(form) + '</code></p>')
|
167 | : ''
|
168 | ) +
|
169 | renderForm((title ? 1 : 0), [], form, blanks, html5, lists) +
|
170 | (html5 ? '</article>' : '</div>')
|
171 | )
|
172 | }
|
173 |
|
174 | function equal (a, b) {
|
175 | return (
|
176 | Array.isArray(a) &&
|
177 | Array.isArray(b) &&
|
178 | a.length === b.length &&
|
179 | a.every(function (_, index) {
|
180 | return a[index] === b[index]
|
181 | })
|
182 | )
|
183 | }
|
184 |
|
185 | function containsAHeading (child) {
|
186 | return (
|
187 | child.hasOwnProperty('heading') ||
|
188 | child.form.content.some(function (element) {
|
189 | return (
|
190 | element.hasOwnProperty('form') &&
|
191 | containsAHeading(element)
|
192 | )
|
193 | })
|
194 | )
|
195 | }
|