Skip to content

Commit 97552e8

Browse files
authored
Merge pull request #170 from HubSpot/match-draft-list-depth-styles
Match ordered list styling from draft-js editor when converting to HTML
2 parents 86dfc4a + 022baa6 commit 97552e8

File tree

4 files changed

+60
-11
lines changed

4 files changed

+60
-11
lines changed

src/convertToHTML.js

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,10 @@ const convertToHTML = ({
6262
if (!blockHTMLResult.nest) {
6363
// this block can't be nested, so reset all nesting if necessary
6464
closeNestTags = listStack.reduceRight((string, nestedBlock) => {
65-
return string + getNestedBlockTags(getBlockHTML(nestedBlock)).nestEnd;
65+
return (
66+
string +
67+
getNestedBlockTags(getBlockHTML(nestedBlock), depth).nestEnd
68+
);
6669
}, '');
6770
listStack = [];
6871
} else {
@@ -73,17 +76,23 @@ const convertToHTML = ({
7376
if (depth + 1 === listStack.length) {
7477
// depth is right but doesn't match type
7578
const blockToClose = listStack[depth];
76-
closeNestTags += getNestedBlockTags(getBlockHTML(blockToClose))
77-
.nestEnd;
78-
openNestTags += getNestedBlockTags(getBlockHTML(block)).nestStart;
79+
closeNestTags += getNestedBlockTags(
80+
getBlockHTML(blockToClose),
81+
depth
82+
).nestEnd;
83+
openNestTags += getNestedBlockTags(getBlockHTML(block), depth)
84+
.nestStart;
7985
listStack[depth] = block;
8086
} else if (depth + 1 < listStack.length) {
8187
const blockToClose = listStack[listStack.length - 1];
82-
closeNestTags += getNestedBlockTags(getBlockHTML(blockToClose))
83-
.nestEnd;
88+
closeNestTags += getNestedBlockTags(
89+
getBlockHTML(blockToClose),
90+
depth
91+
).nestEnd;
8492
listStack = listStack.slice(0, -1);
8593
} else {
86-
openNestTags += getNestedBlockTags(getBlockHTML(block)).nestStart;
94+
openNestTags += getNestedBlockTags(getBlockHTML(block), depth)
95+
.nestStart;
8796
listStack.push(block);
8897
}
8998
}
@@ -120,7 +129,9 @@ const convertToHTML = ({
120129
.join('');
121130

122131
result = listStack.reduce((res, nestBlock) => {
123-
return res + getNestedBlockTags(getBlockHTML(nestBlock)).nestEnd;
132+
return (
133+
res + getNestedBlockTags(getBlockHTML(nestBlock), nestBlock.depth).nestEnd
134+
);
124135
}, result);
125136

126137
return result;

src/default/defaultBlockHTML.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import React from 'react';
22

3+
// based on Draft.js' custom list depth styling
4+
const ORDERED_LIST_TYPES = ['1', 'a', 'i'];
5+
36
export default {
47
unstyled: <p />,
58
paragraph: <p />,
@@ -16,7 +19,10 @@ export default {
1619
},
1720
'ordered-list-item': {
1821
element: <li />,
19-
nest: <ol />,
22+
nest: depth => {
23+
const type = ORDERED_LIST_TYPES[depth % 3];
24+
return <ol type={type} />;
25+
},
2026
},
2127
media: <figure />,
2228
atomic: <figure />,

src/util/getNestedBlockTags.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,20 @@ import invariant from 'invariant';
22
import React from 'react';
33
import splitReactElement from './splitReactElement';
44

5-
export default function getNestedBlockTags(blockHTML) {
5+
export default function getNestedBlockTags(blockHTML, depth) {
66
invariant(
77
blockHTML !== null && blockHTML !== undefined,
88
'Expected block HTML value to be non-null'
99
);
1010

11+
if (typeof blockHTML.nest === 'function') {
12+
const { start, end } = splitReactElement(blockHTML.nest(depth));
13+
return Object.assign({}, blockHTML, {
14+
nestStart: start,
15+
nestEnd: end,
16+
});
17+
}
18+
1119
if (React.isValidElement(blockHTML.nest)) {
1220
const { start, end } = splitReactElement(blockHTML.nest);
1321
return Object.assign({}, blockHTML, {

test/spec/convertToHTML-test.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,31 @@ describe('convertToHTML', () => {
137137
},
138138
]);
139139
const result = convertToHTML(contentState);
140-
expect(result).toBe('<ol><li>item one</li><li>item two</li></ol>');
140+
expect(result).toBe('<ol type="1"><li>item one</li><li>item two</li></ol>');
141+
});
142+
143+
it('applies type attribute for nested ordered lists', () => {
144+
const contentState = buildContentState([
145+
{
146+
type: 'ordered-list-item',
147+
text: 'top level item one',
148+
depth: 0,
149+
},
150+
{
151+
type: 'ordered-list-item',
152+
text: 'sub item one',
153+
depth: 1,
154+
},
155+
{
156+
type: 'ordered-list-item',
157+
text: 'sub-sub item one',
158+
depth: 2,
159+
},
160+
]);
161+
const result = convertToHTML(contentState);
162+
expect(result).toBe(
163+
'<ol type="1"><li>top level item one</li><ol type="a"><li>sub item one</li><ol type="i"><li>sub-sub item one</li></ol></ol></ol>'
164+
);
141165
});
142166

143167
it('nests list items of different depths', () => {

0 commit comments

Comments
 (0)