Search code examples
javascriptms-wordoffice-jsopenxmlword-addins

Underline doesn't display in Ooxml


I am debugging a Word office js add-in. One thing that it needs to do is create a hidden section in the word document. To do this, I pass in some information to a javascript function that creates an OoXML string. I give the user the ability to embed some text in the section, and the user needs to be able to italicize, bold, underline or apply any combination of those formats to the embedded text. Italicization and bolding work fine, but underlining doesn't work.

The embedded text is entered into an html text box in the add-in. The user can click a button to italicize, another button to bold, a third button to underline, or a fourth button to remove those decorations. The click events of the buttons prepend and append html tags, so a string of text which is bolded, italicized and underlined would be sent over like this:

<b><i><u>string of text</u></i></b>

Then another function converts this to Ooxml. The resulting ooxml looks like this:

<w:r> <w:rPr> <w:b /> <w:i /> <w:u /> </w:rPr> <w:instrText xml:space="preserve">string of text</w:instrText> </w:r>

(I can see the ooxml string in my console log).

After the code inserts this into the document, it is bolded and italicized but not underlined. I have tried playing around with the function that generates the code, for example removing the space between the w:u and the />:

<w:r> <w:rPr> <w:b/>  <w:i/> <w:u/> </w:rPr> <w:instrText xml:space="preserve">string of text</w:instrText> </w:r>

I tried removing the trailing backslash on those tags but that broke the range.insertOoxml() call. I've also tried adding a w:val="single" attribute because I wasn't sure if the val was required or not, ie.:

<w:r> <w:rPr> <w:b />  <w:i /> <w:u w:val="single" /> </w:rPr> <w:instrText xml:space="preserve">string of text</w:instrText> </w:r>

I am stumped at this point. The code is agnostic as to what tag is used -- it doesn't care if it's a b, i or u. I understand that <w:b /> and <w:i /> are toggles and <w:u /> may not be -- do I need to handle that differently? Has anyone else run into this issue, and is there something wrong with the Ooxml that someone could point out?

Thank you.

EDIT: To clarify, what I originally included was only the formatting of the text inside the hidden section. Below is the full OoXml the code creates. I am separating the code before and after the original formatted text so you can see where it fits in to the entire OoXml code:

Before the formatted text string:

<pkg:package xmlns:pkg='http://schemas.microsoft.com/office/2006/xmlPackage'><pkg:part pkg:name='/_rels/.rels' pkg:contentType='application/vnd.openxmlformats-package.relationships+xml' pkg:padding='512'><pkg:xmlData><Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'><Relationship Id='rId1' Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' Target='word/document.xml'/></Relationships></pkg:xmlData></pkg:part><pkg:part pkg:name='/word/document.xml' pkg:contentType='application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'><pkg:xmlData><w:document xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' >
<w:body><w:p><w:r> <w:fldChar w:fldCharType='begin' /> </w:r> <w:r><w:rPr><w:color w:val='C00000'/></w:rPr><w:instrText xml:space="preserve">
"XE Startindex_1_id_000014_e"</w:instrText> </w:r> 

The formatted text string:

<w:r> <w:rPr> <w:b /> <w:i /> <w:u /> </w:rPr> <w:instrText xml:space="preserve">string of text</w:instrText> </w:r>

After the formatted text string:

<w:r><w:rPr><w:color w:val='C00000'/></w:rPr><w:instrText xml:space="preserve">"XE Endindex_1_id_000014"</w:instrText> </w:r> <w:r> <w:fldChar w:fldCharType='end' /> </w:r></w:p></w:body></w:document></pkg:xmlData></pkg:part></pkg:package>

Solution

  • While I'm not exactly sure about the requirements on the "hidden section", here are two variants of Open XML markup that Word will render as bolded, italicized, and underlined text.

    Let's start with normal text, for which you would use a w:t element. The text below is not hidden, however. If you wanted to hide it, you'd have to add the w:vanish element to the w:rPr. In that case, Word will render a thin dotted line and not show the normal underline (which should not be used in professionally typeset documents anyhow).

        <w:p>
          <w:r>
            <w:rPr>
              <w:b/>
              <w:i/>
              <w:u w:val="single"/>
            </w:rPr>
            <w:t>string of text</w:t>
          </w:r>
        </w:p>
    

    In your question, you are using the w:instrText element, which is normally part of a complex field. Thus, the next example shows a complex field:

        <w:p>
          <w:r>
            <w:fldChar w:fldCharType="begin"/>
          </w:r>
          <w:r>
            <w:rPr>
              <w:b/>
              <w:i/>
              <w:u w:val="single"/>
            </w:rPr>
            <w:instrText>string of text</w:instrText>
          </w:r>
          <w:r>
            <w:fldChar w:fldCharType="separate"/>
          </w:r>
          <!--
            Note that Word will insert a w:r with an error message (Bookmark not found)
            at this point, if you ever update fields.
            -->
          <w:r>
            <w:fldChar w:fldCharType="end"/>
          </w:r>
        </w:p>
    

    The field code will not normally be shown, so the text is hidden. However, if you update fields, Word will show an error message where you put the field.

    In your question, you did not include the w:r elements with the w:fldChar child elements, so your text will always be visible and also underlined. Further, Word will turn the w:instrText into a w:t, so you'll be back at my first example.

    Update 2020-03-12

    If you want to create an index, this is what you would see in Word if you used the built-in functionality to mark entries and insert an index and also showed paragraph marks:

    Word Index

    If you do not show paragraph marks, the fields used to mark the entries are hidden:

    enter image description here

    I've just formatted the text in the curly braces manually. The key thing to note is that this is an actual XE (index entry) field. So you need to produce the markup for an actual field (as shown in my second example) and make sure the field looks like this (using the first paragraph as an example):

        <w:p>
          <w:r>
            <w:t>This is some</w:t>
          </w:r>
    
          <!-- Your field begins here -->
    
          <w:r>
            <w:fldChar w:fldCharType="begin"/>
          </w:r>
          <w:r>
            <w:instrText xml:space="preserve"> XE "</w:instrText>
          </w:r>
          <w:r>
            <w:rPr>
              <w:i/>
            </w:rPr>
            <w:instrText>Defoe</w:instrText>
          </w:r>
          <w:r>
            <w:instrText xml:space="preserve">, Daniel\; </w:instrText>
          </w:r>
          <w:r>
            <w:rPr>
              <w:b/>
            </w:rPr>
            <w:instrText>Moby Dick</w:instrText>
          </w:r>
          <w:r>
            <w:instrText xml:space="preserve">" </w:instrText>
          </w:r>
          <w:r>
            <w:fldChar w:fldCharType="end"/>
          </w:r>
    
          <!-- Your field ends here -->
    
          <w:r>
            <w:t xml:space="preserve"> text.</w:t>
          </w:r>
        </w:p>
    

    Note that you must escape colons (:) and semicolons (;) in the field code.