diff options
| author | Andreas Lubbe <git@lubbe.org> | 2015-01-23 18:24:23 +0100 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2015-02-09 20:31:51 +0000 |
| commit | 4d4d9e669b389be294373cf3c9bd4727dd5f32af (patch) | |
| tree | d66a47574dfea6c24328aa296cb3b67f2d7890f2 | |
| parent | 37cdbc47dc105a3c745e0f718843e68cf1741aed (diff) | |
Add support for internal hyperlinks
| -rw-r--r-- | lib/document-to-html.js | 15 | ||||
| -rw-r--r-- | lib/documents.js | 14 | ||||
| -rw-r--r-- | lib/docx/document-xml-reader.js | 12 | ||||
| -rw-r--r-- | tests/document-to-html.tests.js | 34 | ||||
| -rw-r--r-- | tests/docx/document-xml-reader.tests.js | 22 |
5 files changed, 84 insertions, 13 deletions
diff --git a/lib/document-to-html.js b/lib/document-to-html.js index c068fba..000fc5c 100644 --- a/lib/document-to-html.js +++ b/lib/document-to-html.js @@ -234,7 +234,9 @@ function DocumentConversion(options) { callback(); }, "hyperlink": function(element, html, messages, callback) { - html.open(htmlPaths.element("a", {href: element.href})); + var href = element.anchor ? "#" + element.anchor : element.href; + + html.open(htmlPaths.element("a", {href: href})); convertElements(element.children, html, messages, function(err) { if (err) { callback(err); @@ -280,6 +282,17 @@ function DocumentConversion(options) { "lineBreak": function(element, html, messages, callback) { html.selfClosing(htmlPaths.element("br")); callback(); + }, + "bookmarkStart": function(element, html, messages, callback) { + if (element.name === "_GoBack") { + return callback(); + } + + html.open(htmlPaths.element("span", { + id: element.name + }), {alwaysWrite: true}); + html.close(); + callback(); } }; return { diff --git a/lib/documents.js b/lib/documents.js index 78bea1a..10d8646 100644 --- a/lib/documents.js +++ b/lib/documents.js @@ -13,7 +13,8 @@ var types = { table: "table", tableRow: "tableRow", tableCell: "tableCell", - lineBreak: "lineBreak" + lineBreak: "lineBreak", + bookmarkStart: "bookmarkStart" }; function Document(children, options) { @@ -74,7 +75,8 @@ function Hyperlink(children, options) { return { type: types.hyperlink, children: children, - href: options.href + href: options.href, + anchor: options.anchor }; } @@ -149,6 +151,13 @@ function LineBreak() { }; } +function BookmarkStart(options) { + return { + type: types.bookmarkStart, + name: options.name + }; +} + exports.Document = Document; exports.Paragraph = Paragraph; exports.Run = Run; @@ -163,5 +172,6 @@ exports.Table = Table; exports.TableRow = TableRow; exports.TableCell = TableCell; exports.LineBreak = LineBreak; +exports.BookmarkStart = BookmarkStart; exports.verticalAlignment = verticalAlignment; diff --git a/lib/docx/document-xml-reader.js b/lib/docx/document-xml-reader.js index e290792..f25e7a3 100644 --- a/lib/docx/document-xml-reader.js +++ b/lib/docx/document-xml-reader.js @@ -167,10 +167,13 @@ function DocumentXmlReader(options) { }, "w:hyperlink": function(element) { var relationshipId = element.attributes["r:id"]; + var anchor = element.attributes["w:anchor"]; return readXmlElements(element.children).map(function(children) { if (relationshipId) { var href = relationships[relationshipId].target; return new documents.Hyperlink(children, {href: href}); + } else if (anchor) { + return new documents.Hyperlink(children, {anchor: anchor}); } else { return children; } @@ -195,7 +198,13 @@ function DocumentXmlReader(options) { return new Result(new documents.LineBreak()); } }, - + "w:bookmarkStart": function(element){ + var name = element.attributes["w:name"]; + return readXmlElements(element.children).map(function(){ + return new documents.BookmarkStart({name: name}); + }); + }, + "w:ins": readChildElements, "w:smartTag": readChildElements, "w:drawing": readChildElements, @@ -245,7 +254,6 @@ var supportedImageTypes = { }; var ignoreElements = { - "w:bookmarkStart": true, "w:bookmarkEnd": true, "w:sectPr": true, "w:proofErr": true, diff --git a/tests/document-to-html.tests.js b/tests/document-to-html.tests.js index 3f50cbd..4863cf1 100644 --- a/tests/document-to-html.tests.js +++ b/tests/document-to-html.tests.js @@ -239,7 +239,18 @@ describe('DocumentConverter', function() { assert.equal(result.value, '<a href="http://www.example.com">Hello.</a>'); }); }); - + + test('docx hyperlink with anchor is converted to <a>', function() { + var hyperlink = new documents.Hyperlink( + [runOfText("Hello.")], + {anchor: "_Peter"} + ); + var converter = new DocumentConverter(); + return converter.convertToHtml(hyperlink).then(function(result) { + assert.equal(result.value, '<a href="#_Peter">Hello.</a>'); + }); + }); + test('docx tab is converted to tab in HTML', function() { var tab = new documents.Tab(); var converter = new DocumentConverter(); @@ -405,6 +416,27 @@ describe('DocumentConverter', function() { assert.equal(result.value.indexOf("<p>Hello.</p>"), 0); }); }); + + test('referenced bookmarks are coverted to anchors', function() { + var bookmarkStart = new documents.BookmarkStart({name: "_Peter"}); + var hyperlink = new documents.Hyperlink( + [runOfText("Hello.")], + {anchor: "_Peter"} + ); + var converter = new DocumentConverter(); + var document = new documents.Document([bookmarkStart, hyperlink]); + return converter.convertToHtml(document).then(function(result) { + assert.equal(result.value, '<span id="_Peter"></span><a href="#_Peter">Hello.</a>'); + }); + }); + + test('unreferenced bookmarks are not converted', function() { + var bookmarkStart = new documents.BookmarkStart({name: "_Unreferenced"}); + var converter = new DocumentConverter(); + return converter.convertToHtml(bookmarkStart).then(function(result) { + assert.equal(result.value, ''); + }); + }); }); function paragraphOfText(text, styleId, styleName) { diff --git a/tests/docx/document-xml-reader.tests.js b/tests/docx/document-xml-reader.tests.js index 0b5a75f..35c806b 100644 --- a/tests/docx/document-xml-reader.tests.js +++ b/tests/docx/document-xml-reader.tests.js @@ -217,12 +217,12 @@ describe("readXmlElement: ", function() { }] ); }); - - test("w:bookmarkStart is ignored without warning", function() { - var ignoredElement = new XmlElement("w:bookmarkStart"); - var result = readXmlElement(ignoredElement); - assert.deepEqual(result.messages, []); - assert.deepEqual([], result.value); + + test("w:bookmarkStart is read as a bookmarkStart", function() { + var bookmarkStart = new XmlElement("w:bookmarkStart", {"w:name": "_Peter", "w:id": "42"}); + var result = readXmlElement(bookmarkStart); + assert.deepEqual(result.value.name, "_Peter"); + assert.deepEqual(result.value.type, "bookmarkStart"); }); test("can read inline pictures", function() { @@ -354,7 +354,15 @@ describe("readXmlElement: ", function() { assert.deepEqual(result.value.href, "http://example.com"); assert.deepEqual(result.value.children[0].type, "run"); }); - + + test("w:hyperlink is read as document hyperlink if it has an anchor", function() { + var runXml = new XmlElement("w:r", {}, []); + var hyperlinkXml = new XmlElement("w:hyperlink", {"w:anchor": "_Peter"}, [runXml]); + var result = readXmlElement(hyperlinkXml); + assert.deepEqual(result.value.anchor, "_Peter"); + assert.deepEqual(result.value.children[0].type, "run"); + }); + test("w:hyperlink is ignored if it does not have a relationship ID", function() { var runXml = new XmlElement("w:r", {}, []); var hyperlinkXml = new XmlElement("w:hyperlink", {}, [runXml]); |
