diff options
| author | Michael Williamson <mike@zwobble.org> | 2016-11-19 14:53:45 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2016-11-19 14:53:45 +0000 |
| commit | a7146d18d1183fbe0203025f5e0e6aee5cd3775c (patch) | |
| tree | 0742a812f4488265ca33ff7221bd97b78c500e53 | |
| parent | 599b3f17555a9d0c03ff040df6dca232b152a6f0 (diff) | |
Include embedded style map when explicit style map is set
| -rw-r--r-- | NEWS | 5 | ||||
| -rw-r--r-- | README.md | 7 | ||||
| -rw-r--r-- | lib/index.js | 24 | ||||
| -rw-r--r-- | lib/options-reader.js | 131 | ||||
| -rw-r--r-- | test/mammoth.tests.js | 11 | ||||
| -rw-r--r-- | test/options-reader.tests.js | 29 |
6 files changed, 119 insertions, 88 deletions
@@ -10,6 +10,11 @@ * Allow a separator to be specified when HTML elements are collapsed. +* Add includeEmbeddedStyleMap option to allow embedded style maps to be + disabled. + +* Include embedded styles when explicit style map is passed. + # 1.2.5 * Ignore bold, italic, underline and strikethrough elements that have a value of @@ -345,6 +345,11 @@ Converts the source document to HTML. each element is expected to be a string representing a single style mapping. See "Writing style maps" for a reference to the syntax for style maps. + * `includeEmbeddedStyleMap`: by default, + if the document contains an embedded style, then it is combined with the default style map. + To ignore any embedded style maps, + set `options.includeEmbeddedStyleMap` to `false`. + * `includeDefaultStyleMap`: by default, the style map passed in `styleMap` is combined with the default style map. To stop using the default style map altogether, @@ -407,7 +412,7 @@ Each paragraph is followed by two newlines. Given an existing docx file, `embedStyleMap` will generate a new docx file with the passed style map embedded. When the new docx file is read by Mammoth, -it will use the embedded style if no explicit style map is provided. +it will use the embedded style map. * `input`: an object describing the source document. On node.js, the following inputs are supported: diff --git a/lib/index.js b/lib/index.js index ae95371..212b0b7 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,3 +1,5 @@ +var _ = require("underscore"); + var docxReader = require("./docx/docx-reader"); var docxStyleMap = require("./docx/style-map"); var DocumentConverter = require("./document-to-html").DocumentConverter; @@ -27,24 +29,21 @@ function convertToMarkdown(input, options) { } function convert(input, options) { - options = Object.create(options || {}); + options = readOptions(options); return unzip.openZip(input) .tap(function(docxFile) { - if (!options.styleMap) { - return docxStyleMap.readStyleMap(docxFile).then(function(styleMap) { - options.styleMap = styleMap || ""; - }); - } + return docxStyleMap.readStyleMap(docxFile).then(function(styleMap) { + options.embeddedStyleMap = styleMap; + }); }) .then(function(docxFile) { - var fullOptions = readOptions(options); return docxReader.read(docxFile, input) .then(function(documentResult) { - return documentResult.map(fullOptions.transformDocument); + return documentResult.map(options.transformDocument); }) .then(function(documentResult) { - return convertDocumentToHtml(documentResult, fullOptions); + return convertDocumentToHtml(documentResult, options); }); }); } @@ -55,9 +54,10 @@ function readEmbeddedStyleMap(input) { } function convertDocumentToHtml(documentResult, options) { - var parsedOptions = Object.create(options); - var styleMapResult = parseStyleMap(options.styleMap); - parsedOptions.styleMap = styleMapResult.value; + var styleMapResult = parseStyleMap(options.readStyleMap()); + var parsedOptions = _.extend({}, options, { + styleMap: styleMapResult.value + }); var documentConverter = new DocumentConverter(parsedOptions); return documentResult.flatMapThen(function(document) { diff --git a/lib/options-reader.js b/lib/options-reader.js index 4a7db9d..e7e94fd 100644 --- a/lib/options-reader.js +++ b/lib/options-reader.js @@ -3,79 +3,81 @@ exports.readOptions = readOptions; var _ = require("underscore"); +var defaultStyleMap = exports._defaultStyleMap = [ + "p.Heading1 => h1:fresh", + "p.Heading2 => h2:fresh", + "p.Heading3 => h3:fresh", + "p.Heading4 => h4:fresh", + "p.Heading5 => h5:fresh", + "p.Heading6 => h6:fresh", + "p[style-name='Heading 1'] => h1:fresh", + "p[style-name='Heading 2'] => h2:fresh", + "p[style-name='Heading 3'] => h3:fresh", + "p[style-name='Heading 4'] => h4:fresh", + "p[style-name='Heading 5'] => h5:fresh", + "p[style-name='Heading 6'] => h6:fresh", + "p[style-name='heading 1'] => h1:fresh", + "p[style-name='heading 2'] => h2:fresh", + "p[style-name='heading 3'] => h3:fresh", + "p[style-name='heading 4'] => h4:fresh", + "p[style-name='heading 5'] => h5:fresh", + "p[style-name='heading 6'] => h6:fresh", + + "r[style-name='Strong'] => strong", + + "p[style-name='footnote text'] => p", + "r[style-name='footnote reference'] =>", + "p[style-name='endnote text'] => p", + "r[style-name='endnote reference'] =>", + "p[style-name='annotation text'] => p", + "r[style-name='annotation reference'] =>", + + // LibreOffice + "p[style-name='Footnote'] => p", + "r[style-name='Footnote anchor'] =>", + "p[style-name='Endnote'] => p", + "r[style-name='Endnote anchor'] =>", + + "p:unordered-list(1) => ul > li:fresh", + "p:unordered-list(2) => ul|ol > li > ul > li:fresh", + "p:unordered-list(3) => ul|ol > li > ul|ol > li > ul > li:fresh", + "p:unordered-list(4) => ul|ol > li > ul|ol > li > ul|ol > li > ul > li:fresh", + "p:unordered-list(5) => ul|ol > li > ul|ol > li > ul|ol > li > ul|ol > li > ul > li:fresh", + "p:ordered-list(1) => ol > li:fresh", + "p:ordered-list(2) => ul|ol > li > ol > li:fresh", + "p:ordered-list(3) => ul|ol > li > ul|ol > li > ol > li:fresh", + "p:ordered-list(4) => ul|ol > li > ul|ol > li > ul|ol > li > ol > li:fresh", + "p:ordered-list(5) => ul|ol > li > ul|ol > li > ul|ol > li > ul|ol > li > ol > li:fresh", + + "r[style-name='Hyperlink'] =>", + + "p[style-name='Normal'] => p:fresh" +]; var standardOptions = exports._standardOptions = { - styleMap: [ - "p.Heading1 => h1:fresh", - "p.Heading2 => h2:fresh", - "p.Heading3 => h3:fresh", - "p.Heading4 => h4:fresh", - "p.Heading5 => h5:fresh", - "p.Heading6 => h6:fresh", - "p[style-name='Heading 1'] => h1:fresh", - "p[style-name='Heading 2'] => h2:fresh", - "p[style-name='Heading 3'] => h3:fresh", - "p[style-name='Heading 4'] => h4:fresh", - "p[style-name='Heading 5'] => h5:fresh", - "p[style-name='Heading 6'] => h6:fresh", - "p[style-name='heading 1'] => h1:fresh", - "p[style-name='heading 2'] => h2:fresh", - "p[style-name='heading 3'] => h3:fresh", - "p[style-name='heading 4'] => h4:fresh", - "p[style-name='heading 5'] => h5:fresh", - "p[style-name='heading 6'] => h6:fresh", - - "r[style-name='Strong'] => strong", - - "p[style-name='footnote text'] => p", - "r[style-name='footnote reference'] =>", - "p[style-name='endnote text'] => p", - "r[style-name='endnote reference'] =>", - "p[style-name='annotation text'] => p", - "r[style-name='annotation reference'] =>", - - // LibreOffice - "p[style-name='Footnote'] => p", - "r[style-name='Footnote anchor'] =>", - "p[style-name='Endnote'] => p", - "r[style-name='Endnote anchor'] =>", - - "p:unordered-list(1) => ul > li:fresh", - "p:unordered-list(2) => ul|ol > li > ul > li:fresh", - "p:unordered-list(3) => ul|ol > li > ul|ol > li > ul > li:fresh", - "p:unordered-list(4) => ul|ol > li > ul|ol > li > ul|ol > li > ul > li:fresh", - "p:unordered-list(5) => ul|ol > li > ul|ol > li > ul|ol > li > ul|ol > li > ul > li:fresh", - "p:ordered-list(1) => ol > li:fresh", - "p:ordered-list(2) => ul|ol > li > ol > li:fresh", - "p:ordered-list(3) => ul|ol > li > ul|ol > li > ol > li:fresh", - "p:ordered-list(4) => ul|ol > li > ul|ol > li > ul|ol > li > ol > li:fresh", - "p:ordered-list(5) => ul|ol > li > ul|ol > li > ul|ol > li > ul|ol > li > ol > li:fresh", - - "r[style-name='Hyperlink'] =>", - - "p[style-name='Normal'] => p:fresh" - - ], transformDocument: identity, - includeDefaultStyleMap: true + includeDefaultStyleMap: true, + includeEmbeddedStyleMap: true }; function readOptions(options) { options = options || {}; - var fullOptions = {}; - _.extend(fullOptions, standardOptions, options); - - fullOptions.styleMap = readStyleMap(options.styleMap, fullOptions); - - return fullOptions; + return _.extend({}, standardOptions, options, { + customStyleMap: readStyleMap(options.styleMap), + readStyleMap: function() { + var styleMap = this.customStyleMap; + if (this.includeEmbeddedStyleMap) { + styleMap = styleMap.concat(readStyleMap(this.embeddedStyleMap)); + } + if (this.includeDefaultStyleMap) { + styleMap = styleMap.concat(defaultStyleMap); + } + return styleMap; + } + }); } -function readStyleMap(styleMap, options) { - var customStyleMap = readCustomStyleMap(styleMap); - return customStyleMap.concat(options.includeDefaultStyleMap ? standardOptions.styleMap : []); -} - -function readCustomStyleMap(styleMap) { +function readStyleMap(styleMap) { if (!styleMap) { return []; } else if (_.isString(styleMap)) { @@ -91,7 +93,6 @@ function readCustomStyleMap(styleMap) { } } - function identity(value) { return value; } diff --git a/test/mammoth.tests.js b/test/mammoth.tests.js index db2b338..19e0c47 100644 --- a/test/mammoth.tests.js +++ b/test/mammoth.tests.js @@ -100,6 +100,17 @@ test('explicit style map takes precedence over embedded style map', function() { }); }); +test('embedded style maps can be disabled', function() { + var docxPath = path.join(__dirname, "test-data/embedded-style-map.docx"); + var options = { + includeEmbeddedStyleMap: false + }; + return mammoth.convertToHtml({path: docxPath}, options).then(function(result) { + assert.equal(result.value, "<p>Walking on imported air</p>"); + assert.deepEqual(result.messages, []); + }); +}); + test('embedded style map can be written and then read', function() { var docxPath = path.join(__dirname, "test-data/single-paragraph.docx"); return promises.nfcall(fs.readFile, docxPath) diff --git a/test/options-reader.tests.js b/test/options-reader.tests.js index b0f202b..bad4c56 100644 --- a/test/options-reader.tests.js +++ b/test/options-reader.tests.js @@ -1,5 +1,7 @@ var assert = require("assert"); +var _ = require("underscore"); + var optionsReader = require("../lib/options-reader"); var standardOptions = optionsReader._standardOptions; var readOptions = optionsReader.readOptions; @@ -7,42 +9,49 @@ var test = require("./test")(module); test('standard options are used if options is undefined', function() { - assert.deepEqual(standardOptions, readOptions(undefined)); + var options = readOptions(undefined); + assert.deepEqual(standardOptions, _.omit(options, "customStyleMap", "readStyleMap")); + assert.deepEqual(options.customStyleMap, []); }); test('standard options are used if options is empty', function() { - assert.deepEqual(standardOptions, readOptions({})); + var options = readOptions({}); + assert.deepEqual(standardOptions, _.omit(options, "customStyleMap", "readStyleMap")); + assert.deepEqual(options.customStyleMap, []); }); test('custom style map as string is prepended to standard style map', function() { var options = readOptions({ styleMap: "p.SectionTitle => h2" }); - assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]); - assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1)); + var styleMap = options.readStyleMap(); + assert.deepEqual("p.SectionTitle => h2", styleMap[0]); + assert.deepEqual(optionsReader._defaultStyleMap, styleMap.slice(1)); }); test('custom style map as array is prepended to standard style map', function() { var options = readOptions({ styleMap: ["p.SectionTitle => h2"] }); - assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]); - assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1)); + var styleMap = options.readStyleMap(); + assert.deepEqual("p.SectionTitle => h2", styleMap[0]); + assert.deepEqual(optionsReader._defaultStyleMap, styleMap.slice(1)); }); test('lines starting with # in custom style map are ignored', function() { var options = readOptions({ styleMap: "# p.SectionTitle => h3\np.SectionTitle => h2" }); - assert.deepEqual("p.SectionTitle => h2", options.styleMap[0]); - assert.deepEqual(standardOptions.styleMap, options.styleMap.slice(1)); + var styleMap = options.readStyleMap(); + assert.deepEqual("p.SectionTitle => h2", styleMap[0]); + assert.deepEqual(optionsReader._defaultStyleMap, styleMap.slice(1)); }); test('blank lines in custom style map are ignored', function() { var options = readOptions({ styleMap: "\n\n" }); - assert.deepEqual(standardOptions.styleMap, options.styleMap); + assert.deepEqual(optionsReader._defaultStyleMap, options.readStyleMap()); }); test('default style mappings are ignored if includeDefaultStyleMap is false', function() { @@ -50,5 +59,5 @@ test('default style mappings are ignored if includeDefaultStyleMap is false', fu styleMap: "p.SectionTitle => h2", includeDefaultStyleMap: false }); - assert.deepEqual(["p.SectionTitle => h2"], options.styleMap); + assert.deepEqual(["p.SectionTitle => h2"], options.readStyleMap()); }); |
