diff --git a/CHANGELOG.md b/CHANGELOG.md index 8484fc9a..a24e1063 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ### Unreleased - Add subset for PDF/UA +- Fix for line breaks in list items (#1486) ### [v0.14.0] - 2023-11-09 diff --git a/lib/mixins/text.js b/lib/mixins/text.js index a1c7f425..d78f4465 100644 --- a/lib/mixins/text.js +++ b/lib/mixins/text.js @@ -153,73 +153,80 @@ export default { } }; - wrapper = new LineWrapper(this, options); - wrapper.on('line', this._line); + const drawListItem = function(listItem) { + wrapper = new LineWrapper(this, options); + wrapper.on('line', this._line); + + level = 1; + let i = 0; + wrapper.once('firstLine', () => { + let item, itemType, labelType, bodyType; + if (options.structParent) { + if (options.structTypes) { + [itemType, labelType, bodyType] = options.structTypes; + } else { + [itemType, labelType, bodyType] = ['LI', 'Lbl', 'LBody']; + } + } - level = 1; - let i = 0; - wrapper.on('firstLine', () => { - let item, itemType, labelType, bodyType; - if (options.structParent) { - if (options.structTypes) { - [ itemType, labelType, bodyType ] = options.structTypes; - } else { - [ itemType, labelType, bodyType ] = [ 'LI', 'Lbl', 'LBody' ]; + if (itemType) { + item = this.struct(itemType); + options.structParent.add(item); + } else if (options.structParent) { + item = options.structParent; } - } - if (itemType) { - item = this.struct(itemType); - options.structParent.add(item); - } else if (options.structParent) { - item = options.structParent; - } + let l; + if ((l = levels[i++]) !== level) { + const diff = itemIndent * (l - level); + this.x += diff; + wrapper.lineWidth -= diff; + level = l; + } - let l; - if ((l = levels[i++]) !== level) { - const diff = itemIndent * (l - level); - this.x += diff; - wrapper.lineWidth -= diff; - level = l; - } + if (item && (labelType || bodyType)) { + item.add(this.struct(labelType || bodyType, + [this.markStructureContent(labelType || bodyType)])); + } + switch (listType) { + case 'bullet': + this.circle(this.x - indent + r, this.y + midLine, r); + this.fill(); + break; + case 'numbered': + case 'lettered': + var text = label(numbers[i - 1]); + this._fragment(text, this.x - indent, this.y, options); + break; + } - if (item && (labelType || bodyType)) { - item.add(this.struct(labelType || bodyType, - [ this.markStructureContent(labelType || bodyType) ])); - } - switch (listType) { - case 'bullet': - this.circle(this.x - indent + r, this.y + midLine, r); - this.fill(); - break; - case 'numbered': - case 'lettered': - var text = label(numbers[i - 1]); - this._fragment(text, this.x - indent, this.y, options); - break; - } + if (item && labelType && bodyType) { + item.add(this.struct(bodyType, [this.markStructureContent(bodyType)])); + } + if (item && item !== options.structParent) { + item.end(); + } + }); - if (item && labelType && bodyType) { - item.add(this.struct(bodyType, [ this.markStructureContent(bodyType) ])); - } - if (item && item !== options.structParent) { - item.end(); - } - }); + wrapper.on('sectionStart', () => { + const pos = indent + itemIndent * (level - 1); + this.x += pos; + return (wrapper.lineWidth -= pos); + }); - wrapper.on('sectionStart', () => { - const pos = indent + itemIndent * (level - 1); - this.x += pos; - return (wrapper.lineWidth -= pos); - }); + wrapper.on('sectionEnd', () => { + const pos = indent + itemIndent * (level - 1); + this.x -= pos; + return (wrapper.lineWidth += pos); + }); + + wrapper.wrap(listItem, options); + }; - wrapper.on('sectionEnd', () => { - const pos = indent + itemIndent * (level - 1); - this.x -= pos; - return (wrapper.lineWidth += pos); - }); - wrapper.wrap(items.join('\n'), options); + for (let i = 0; i < items.length; i++) { + drawListItem.call(this, items[i]); + } return this; }, diff --git a/tests/visual/__image_snapshots__/text-spec-js-text-list-with-line-breaks-in-items-1-snap.png b/tests/visual/__image_snapshots__/text-spec-js-text-list-with-line-breaks-in-items-1-snap.png new file mode 100644 index 00000000..fb76940d Binary files /dev/null and b/tests/visual/__image_snapshots__/text-spec-js-text-list-with-line-breaks-in-items-1-snap.png differ diff --git a/tests/visual/text.spec.js b/tests/visual/text.spec.js index ec6de8e6..e4e089da 100644 --- a/tests/visual/text.spec.js +++ b/tests/visual/text.spec.js @@ -43,4 +43,11 @@ describe('text', function() { doc.fillColor('#000').list(['One', 'Two', 'Three'], 100, 150); }); }); + + test('list with line breaks in items', function() { + return runDocTest(function(doc) { + doc.font('tests/fonts/Roboto-Regular.ttf'); + doc.list(['Foo\nBar', 'Foo\rBar', 'Foo\r\nBar'], [100, 150]); + }) + }) });