Skip to content

Commit 6dc6870

Browse files
committed
[BUGFIX] Treat classes as attributes to be merged, not appended
1 parent 5650923 commit 6dc6870

File tree

4 files changed

+60
-19
lines changed

4 files changed

+60
-19
lines changed

src/result.js

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,11 @@ class Result {
5151
return insertIntoIndexHTML(
5252
this._html,
5353
this._htmlAttributes,
54+
this._htmlClass,
5455
this._head,
5556
this._body,
56-
this._bodyAttributes
57+
this._bodyAttributes,
58+
this._bodyClass
5759
);
5860
}
5961

@@ -72,9 +74,11 @@ class Result {
7274
return insertIntoIndexHTML(
7375
this._html,
7476
this._htmlAttributes,
77+
this._htmlClass,
7578
this._head,
7679
this._body,
77-
this._bodyAttributes
80+
this._bodyAttributes,
81+
this._bodyClass
7882
).then(html => {
7983
let docParts = html.match(HTML_HEAD_REGEX);
8084
if (!docParts || docParts.length === 1) {
@@ -173,17 +177,13 @@ class Result {
173177
let head = this._doc.head;
174178
let body = this._doc.body;
175179

176-
if (htmlElement.attributes.length > 0) {
177-
this._htmlAttributes = HTMLSerializer.attributes(htmlElement.attributes);
178-
} else {
179-
this._htmlAttributes = null;
180-
}
180+
let { klass: htmlClass, attributes: htmlAttributes } = extractExtraAttributes(htmlElement);
181+
this._htmlClass = htmlClass;
182+
this._htmlAttributes = htmlAttributes;
181183

182-
if (body.attributes.length > 0) {
183-
this._bodyAttributes = HTMLSerializer.attributes(body.attributes);
184-
} else {
185-
this._bodyAttributes = null;
186-
}
184+
let { klass: bodyClass, attributes: bodyAttributes } = extractExtraAttributes(body);
185+
this._bodyClass = bodyClass;
186+
this._bodyAttributes = bodyAttributes;
187187

188188
if (head) {
189189
head = HTMLSerializer.serializeChildren(head);
@@ -198,13 +198,44 @@ class Result {
198198
}
199199
}
200200

201+
function extractExtraAttributes(element) {
202+
let klass;
203+
let attributes;
204+
if (element.attributes.length > 0) {
205+
let elementClass = element.attributes.find(attr => attr.name === 'class');
206+
if (elementClass) {
207+
klass = elementClass;
208+
let otherAttrs = element.attributes.filter(attr => attr.name !== 'class');
209+
if (otherAttrs.length > 0) {
210+
attributes = HTMLSerializer.attributes(otherAttrs);
211+
} else {
212+
attributes = null;
213+
}
214+
} else {
215+
attributes = HTMLSerializer.attributes(element.attributes);
216+
klass = null;
217+
}
218+
} else {
219+
klass = attributes = null;
220+
}
221+
return { klass, attributes };
222+
}
223+
201224
function missingTag(tag) {
202225
throw new Error(
203226
`Fastboot was not able to find ${tag} in base HTML. It could not replace the contents.`
204227
);
205228
}
206229

207-
async function insertIntoIndexHTML(html, htmlAttributes, head, body, bodyAttributes) {
230+
async function insertIntoIndexHTML(
231+
html,
232+
htmlAttributes,
233+
htmlClass,
234+
head,
235+
body,
236+
bodyAttributes,
237+
bodyClass
238+
) {
208239
if (!html) {
209240
return Promise.resolve(html);
210241
}
@@ -222,12 +253,22 @@ async function insertIntoIndexHTML(html, htmlAttributes, head, body, bodyAttribu
222253
return '';
223254
});
224255

256+
if (htmlClass) {
257+
html = html.replace(/(<html.*)class=\"([^"]*)\"([^>]*)/i, function(_, prefix, klass, suffix) {
258+
return prefix + `class="${klass + ' ' + htmlClass.value}"` + suffix;
259+
});
260+
}
225261
if (htmlAttributes) {
226262
html = html.replace(/<html[^>]*/i, function(match) {
227263
return match + ' ' + htmlAttributes;
228264
});
229265
}
230266

267+
if (bodyClass) {
268+
html = html.replace(/(<body.*)class=\"([^"]*)\"([^>]*)/i, function(_, prefix, klass, suffix) {
269+
return prefix + `class="${klass + ' ' + bodyClass.value}"` + suffix;
270+
});
271+
}
231272
if (bodyAttributes) {
232273
html = html.replace(/<body[^>]*/i, function(match) {
233274
return match + ' ' + bodyAttributes;

test/fastboot-test.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ describe('FastBoot', function() {
125125
.visit('/')
126126
.then(r => r.html())
127127
.then(html => {
128-
expect(html).to.match(/<html data-foo=1 +class="it-works"/);
128+
expect(html).to.match(/<html data-before=1 +class="a b it-works" data-after=2/);
129129
});
130130
});
131131

@@ -138,7 +138,7 @@ describe('FastBoot', function() {
138138
.visit('/')
139139
.then(r => r.html())
140140
.then(html => {
141-
expect(html).to.match(/<body data-foo=1 +class="it-works"/);
141+
expect(html).to.match(/<body data-before=1 +class="no-js default-class it-works" data-after=2/);
142142
});
143143
});
144144

test/fixtures/custom-body-attrs/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414
</head>
15-
<body class="no-js" data-foo=1>
15+
<body data-before=1 class="no-js default-class" data-after=2>
1616
<!-- EMBER_CLI_FASTBOOT_BODY -->
1717

1818
<script src="/assets/vendor.js"></script>
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
<!DOCTYPE html>
2-
<html data-foo=1>
2+
<html data-before=1 class="a b" data-after=2>
33
<head>
44
<meta charset="utf-8">
55
<meta http-equiv="X-UA-Compatible" content="IE=edge">
66
<title>FastbootTest</title>
77
<meta name="description" content="">
88
<meta name="viewport" content="width=device-width, initial-scale=1">
99

10-
10+
1111
<!-- EMBER_CLI_FASTBOOT_TITLE --><!-- EMBER_CLI_FASTBOOT_HEAD -->
1212

1313

@@ -18,6 +18,6 @@
1818
<script src="/assets/vendor.js"></script>
1919
<script src="/assets/fastboot-test.js"></script>
2020

21-
21+
2222
</body>
2323
</html>

0 commit comments

Comments
 (0)