In the last four installments, the basics of creating a Web Add-in and reading/inserting information was introduced, using two different data formats: matrix and plain text. When working with Word, especially, formatting can be just as important as text content. For this reason, Word supports more and complexer content types than the other Office applications. This post focuses on using these coercion types in a Web Add-in.

The Visual Studio “Office App” template serves as the basis for this example: changes were made to Home.html and Home.js. The task pane provides radio buttons for selecting the coercion type, a text field for entering content to be inserted into the Word document and buttons for reading and writing to the current selection.
WdCT_1

Here’s the div of the HTML comprising the form and buttons:

<div id="content-main">
        <div class="padding">
            <p><strong>Testing coercion types in Word</strong></p>
            <form> <fieldset>
    <legend>Choose the text formatting type:</legend>
    <input type="radio" name="formats" value="Plain" id="Plain" />
    <label for="Plain text">Plain</label><br />
    <input type="radio" name="formats" value="HTML" id="HTML" />
    <label for="HTML">HTML</label><br />
    <input type="radio" name="formats" value="OOXML" id="OOXML" />
    <label for="OOXML">Word Open XML</label><br/>
                <p>Enter text to insert with formatting tags.</p>
    <textarea id="formatInput" rows="5" cols="30"> </textarea>
</fieldset> <br></form> 
    <p>Test the functionality:</p>
    <button id="getOOXMLString">Get Word Open XML of the selection</button>
    <button id="writeText">Insert text of specified format type</button>
        </div>

The JavaScript code follows below. It’s somewhat oddly formatted in order to fit the page display.

Thinking back to the post about scope, notice how the JavaScript code for the Web Add-in is all within a function – nothing but this function is exposed globally.

At the top of the function is a directive that hasn’t been used in any sample JavaScript in this series, before: "use strict";. This is new in ECMAScript5 and is a bit like using Option Explicit at the top of a VBA module. Strictly speaking, you wouldn’t need it and could leave it out, just as you could (but wouldn’t) leave out Option Explicit.

Office.initialize you should recognize from the “Hello World” code analysis. The use of jQuery extends also to the declaration of the two button click-events (compare the html with the identifying text following the hash-sign) which will be assigned as soon as the web page in the task pane has been loaded. The click events call the two functions writeFormattedText and getFormattedText, discussed below the code section.

(function () {
    "use strict";

    // The initialize function must be run each time a new page is loaded
    Office.initialize = function (reason) {
        $(document).ready(function () {
            app.initialize();

            $('#writeText').click(writeFormattedText);
            $('#getOOXMLString').click(getFormattedText);
        });
    };
//The Word Open XML assigned to sOOXML should all be on one line!
//It's broken up here for the page display.

var sOOXML = "<?xml version='1.0' standalone='yes'?>
<?mso-application progid='Word.Document'?><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:o='urn:schemas-microsoft-com:office:office' 
xmlns:r='http://schemas.openxmlformats.org/officeDocument/2006/relationships' 
xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main' >
<w:body><w:p><w:r><w:rPr><w:b/></w:rPr><w:t>This</w:t></w:r><w:r>
<w:t xml:space='preserve'> is a </w:t></w:r>
<w:r><w:rPr><w:i/></w:rPr><w:t>test</w:t></w:r>
<w:r><w:t>.</w:t></w:r></w:p>
<w:sectPr><w:pgSz w:w='12240' w:h='15840'/><w:pgMar w:top='1440' w:right='1440' 
w:bottom='1440' w:left='1440' w:header='720' w:footer='720' w:gutter='0'/>
<w:cols w:space='720'/></w:sectPr></w:body></w:document>
</pkg:xmlData></pkg:part></pkg:package>"

// Reads data from current document selection and displays a notification
    function getFormattedText() {
        Office.context.document.getSelectedDataAsync(Office.CoercionType.Ooxml,
            function(result) {
                if (result.status === Office.AsyncResultStatus.Succeeded) {
                    //sOOXML = result.value
                    app.showNotification('Selection Word Open XML:', sOOXML);
                } else {
                    app.showNotification('Error:', result.error.message);
                }
            })
    }
    function writeFormattedText() {
        var formatType = $('input:radio[name=formats]:checked').val();
        var coercType;
        var textValue = $('textArea[id=formatInput]').val();
        switch (formatType) {
            case "HTML":
                coercType = Office.CoercionType.Html;
                break;
            case "OOXML":
                coercType = Office.CoercionType.Ooxml;
                textValue = sOOXML;
                break;
            default: //"Plain"
                coercType = Office.CoercionType.Text;
                break;
        }
 //For debugging purposes, in case something's weird.
 // Remove the comment slashes and
 //set a break point at this line as you would in the VBA IDE.
 //Execution will stop and you can view the values in the variables
 //in VS "Locals" window (bottom left, by default).
 //console.log(formatType + " " + coercType.toString() + " " + textValue);
        Office.context.document.setSelectedDataAsync(textValue, 
            { coercionType: coercType },
            function (result) {
                if (result.status === Office.AsyncResultStatus.Succeeded) {
                    app.showNotification('Following was written to the document',
                                          '"' + textValue + '"');
                } else {
                    app.showNotification('Error:', result.error.message);
                }
            }
        );
    }
})();

Let’s first look at writeFormattedText. The first variable, formatType, is assigned the value of the radio button that has been checked in the formats group. The second variable will be assigned the Office.CoercionType for the chosen radio button. The variable textValue reads the formatted text content entered in the text box.

A switch evaluation follows that assigns the CoercionType based on the chosen radio button.

The function then attempts to write the text to the selection in the document using the specified formatting type. The plain text option you’ve seen used in the VS template sample. All you need to do for that is type something in the text box and exactly that will be inserted.

For the HTML option valid HTML is required, for example: This is bold and this is italic. Word will convert this just as if you had copied it from a web page and pasted it into a document. If you had a rich text control that returned valid HTML you could use this to get formatted text input from the user. Or you could have a “library” of HTML snippets to insert formatted content, as required.
WdCT_2
Of the three options, the one for Word Open XML is both the most difficult and the most powerful to work with. This allows you to insert pretty much anything into the document that Word supports… if you have the correct syntax. Unfortunately, Word Open XML isn’t as simple to construct as HTML!

You can see sample Word Open XML assigned to the variable sOOXML in the function. The result of inserting this is: This is a test. If you select the radio button for Word Open XML with the above code, as it stands after removing the line breaks in the Word Open XML, this is what will be inserted.

The question presents itself: how do you find out what the valid Word Open XML is for particular content? That’s what the function getFormattedText is for. Remove the comment slashes from sOOXML = result.value and the full Word Open XML will be stored in the variable. Clicking the button to insert Word Open XML should then write the same content back to the current selection.
WdCT_3
If you look at the Word Open XML that is written to the notification area you’ll see that it contains a lot more than what’s assigned to sOOXML. Word writes a “full” version, but can make do with a lot less. If what you need to insert follows a particular pattern it’s possible to strip the Word Open XML down to only what is needed and break it up into sections so that you can, for example, plug in different text.

It’s of course difficult to see the Word Open XML in the notification area, so you might prefer writing it to a Word document, where you can also edit it. That’s very simple to do with VBA, either to the same document (code below) or a new one:
Sub WriteSelectionWordOpenXML()
Dim sXML As String
Dim rngTarget As word.Range

sXML = Selection.WordOpenXML
Set rngTarget = ActiveDocument.content
rngTarget.Collapse wdCollapseEnd
rngTarget.Text = sXML
End Sub

What can be trimmed out of Word Open XML would be another topic, entirely, which I’d be happy to attempt if there’s sufficient interest.

(Here’s a blog article might be of interest to those curious about using OOXML.)

Leave a Reply