Microsoft 365 Add-ins

Office Add-ins community call–August 12, 2020 

August’s call, hosted by Alex Jerabek, featured the following presenters and topics: 

  • Juan Balmori Labra showcased the Outlook JavaScript APIs coming to the next version of office.js. 
  • Matt Geimer demoed the new single sign-on support in Office Add-ins.  
  • Chris Mentor shared Jedox’s add-in solutions and talked with their team about the experience of building on the platform. 

Watch the call here. 

Developer Survey
We want to hear about your experiences building on the Office Platform. Head over to https://aka.ms/officedevsatisfaction to take a quick survey. 

Q&A

We welcome you to submit questions and topic suggestions in advance of each call by using our short survey form.   

How can I add a shortcut key to a Word Add-in Command? 

Custom keyboard shortcuts are currently not supported for Office Add-ins on Word.  

However, for ribbon buttons (add-in commands) you can use the auto-generated KeyTips by pressing Alt and using the appropriate keys that pop up in the KeyTips for that specific ribbon tab and buttons. 

How can an action (menu item, button) on the Word side execute a JavaScript function in the Add-in? 

Add-in commands can be used to invoke add-in related actions such as showing a task pane or executing a JavaScript function in the add-in. 

Would love to hear more about timelines for Webview2 rolling out with Office and any news about improved debugging support from VS Code. 

Edge WebView2 is now available in Office Insiders. Here are the steps to try out the preview version: 

  • Join the Office Insiders, if you aren’t already part of it [https://insider.office.com/en-us/ 
  • Get Office 365 version 16.0.13127.20082 [or later]  
  • Get the Edge WebView2 runtime from aka.ms/webview2installer 
  • Launch your add-in, right click and you should see an option to “Debug”. 
    Selecting this option should launch the new Edge Webview2 debugger.  
  • Test your add-in and give us feedback on github [https://github.com/officedev]. 

As for debugging support, we would hope to have great debugging capabilities including VS Code debugging. One of the really nice things about the Webview2 control is you’ll also be able to simply right click and inspect like you can do in the web apps. 

Does this SSO use MSAL, if so does it use Implicit Flow or PKCE ? 

It depends on the client as to the library it uses. As of now, its using Implicit flow 

With the new SSO features, if we want to limit our add-ins to Office 365 users (disallow Live accounts), is that possible? 

Its something we are looking in to, but don’t have it as part of the GA. Would love to know if there are other options you need around account types. You can limit the service app registration to work only for organizational accounts. 

Is there an SSO-related eventhat fires when user switches accounts? 

Currently, there isn’t an event that lets you know a user switch happened around SSO, but its something we are looking in to.  

Is this SSO capability only limited to AzureAD? What if customers use other iDPs? 

Yes, SSO support is limited to AzureAD services. at current time. Other identity providers would still need to be handled via the same method we handle fallback – primarily the dialog API. 

Any update on connecting custom functions to asp.net servers? 

For your CORS/Preflight, we’d recommend checking the shared runtime: https://docs.microsoft.com/en-us/office/dev/add-ins/excel/configure-your-add-in-to-use-a-shared-runtime. This will support Full CORS for custom functions. 

Is there a plan to add more than one function (createPresentation) to Powerpoint JavaScript API? 

Our team is investigating new APIs right now, if you have specific asks on APIs, please log issues on our UserVoice site: https://officespdev.uservoice.com.   

Is there or will there be an onSave or beforeSave event as in VSTO, allowing process to be implemented before a document is save? Same for onClose or beforeClose. 

It’s something we’re thinking about. Currently this is a challenge as our model for Office.js runs code asynchronously. This gives users greater control, but makes it difficult to catch events before they happen. So, we’re thinking of different ways to unblock these scenarios. 

When are you likely to get feature parity between VBA and Office.js APIs? 

This is both a great aspirational and inspirational question. Strictly speaking, we might never reach parity, because the Web Add-in Model is intended to be used across the platforms where Office is supported, and in VBA there are hundreds of members that are not multiplatform compatible (e.g., Application level stuff, multi window hosts, COM interoperability, among many others). So, from that perspective its possible they will never be identical. On the other hand, the team is doing a very bold investment to enable as much as possible the most common development scenarios. In Excel, this is close to 70% of the functional capabilities of VBA (that can be multiplatform). That is literally thousands of APIs that have been added in the last years. It’s our aspiration to be growing the API set as needed and for each application using this approach. Right now, the focus is on Excel and Outlook. 

Do you have any plans to extend the Word API so that you can make pages landscape/portrait or programmatically change the margins? It seems you cannot go this even using OOXML. This can be done in the COM API and is blocking our migration to Office.js. 

This is a great question. Effectively, this is a gap in the Word.js API, but I have seen many customers implementing it is using OOXML, so it should not be a blocker in your case. Margins, and ultimately orientation of pageare defined within sections of a document, and sections are defined on the last paragraph of itSo, the basic strategy is to insert an OOXML that defines a section with the desired margins, and then the content that is expected to be accommodated in the boundaries of the defined section (in the right margins) This requires the insertion of at least 2 OOXMLs one with the margin definitions, and another one with the actual content.  

Here is how the margins OOXML needs to be defined and the JS code to make the magic. Note that if you have more sections (i.e., a document with different margin definitions) you will have to repeat as needed 

  1. The OOXML the defines the margins should look like the one below; I will call this one margins.xml. Please note the trick here is that there are 2 paragraphs, the idea is that after insertion we will delete the first paragraph so that it keeps the last paragraph includes the section definition including margins 
<?mso-application progid="Word.Document"?>

<w:wordDocument xmlns:w="http://schemas.microsoft.com/office/word/2003/wordml" w:macrosPresent="no" w:embeddedObjPresent="no" w:ocxPresent="no" xml:space="preserve">

    <w:body>

        <w:p>

            <w:pPr>

                <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:docGrid w:line-pitch="360"/>

                </w:sectPr>

            </w:pPr>

            <w:r>

                <w:t xml:space="preserve"></w:t>

            </w:r>

        </w:p>

        <w:p/>

        <w:p/>

        <w:p>

            <w:pPr>

                <w:sectPr>

                    <w:type w:val="continuous"/>

                    <w:pgSz w:w="12240" w:h="20160"/>

                    <w:pgMar w:top="1418" w:right="1701" w:bottom="1418" w:left="3402" w:header="709" w:footer="709" w:gutter="0"/>

                    <w:cols w:space="708"/>

                    <w:docGrid w:line-pitch="360"/>

                </w:sectPr>

            </w:pPr>

        </w:p>

        <w:sectPr>

            <w:type w:val="continuous"/>

            <w:pgSz w:w="12240" w:h="15840"/>

            <w:pgMar w:top="1418" w:right="1701" w:bottom="1418" w:left="3402" w:header="709" w:footer="709" w:gutter="0"/>

            <w:cols w:space="720"/>

            <w:docGrid w:line-pitch="360"/>

        </w:sectPr>

    </w:body>

</w:wordDocument>

2. The OOXML of the document that needs to be accommodated in those margins. (the section definition must match the previous one), on this example is called ooXmlDocument

3. Optionally the headers.xml OOXML in case your document has headers and again they must match the margins definitions as well, otherwise the document will look “moved”. In this sample, it’s called ooXmlHeader.

Now that you have the needed OOXMLs, you just need to insert them in the right order, doing exactly as the sample below.

function insertDocWithNewMargins() {


         //first, we clear the document. (if needed)
         Word.run(function (context) {
             context.document.body.clear();
             var mySections = context.document.sections;
             context.load(mySections);
             return context.sync()
             .then(function () {
                 for (var i = 0; i < mySections.items.length; i++) {
                     mySections.items[i].getHeader("primary").clear();
                     mySections.items[i].getFooter("primary").clear();
                 }
                 return context.sync()
                 .then(function () {


                     //then we insert the margins.xml (OOXML including margin definitions. )
                    Office.context.document.setSelectedDataAsync(ooXmlMargins, { coercionType: 'ooxml' }, function (result) {
                         if (result.status == "succeeded") {
                             //deletes the first paragraph, so the margins adjust to the last paragraph definition. 
                             Word.run(function (context) {
                                 var myPars = context.document.body.paragraphs;
                                 context.load(myPars);
                                 return context.sync()
                                 .then(function () {
                                     var last = myPars.items.length;
                                     myPars.items[0].delete(); 
                                     return context.sync()


                                         .then(function () {
                                             // the marings OOXML includes a carriage return indicating the exact position where we need to 
                                             //insert the document.xml, via search we find this position. 
                                             var results = context.document.body.search(String.fromCharCode(13, 12, 13));
                                             context.load(results, {expand:'font'});
                                             return context.sync()
                                             .then(function () {
                                                 results.items[0].delete();
                                                 return context.sync()
                                                 .then(function () {
                                                     //time to insert the document.
                                                     Office.context.document.setSelectedDataAsync(ooXmlDocument, { coercionType: 'ooxml' }, function (result) {
                                                         if (result.status == "succeeded") {
                                                             //if you have headers, insert the headers
                                                             Word.run(function (context) {
                                                                 var mySections = context.document.sections;
                                                                 context.load(mySections);
                                                                 return context.sync()
                                                                 .then(function () {
                                                                     mySections.items[0].getHeader("primary").insertOoxml(ooXmlHeader, "replace");
                                                                     return context.sync()
                                                                  .then(function () {
                                                                      console.log("Success!!");
                                                                  })
                                                                 })
                                                             }).catch(function (e) {
                                                                 console.log(e.message);
                                                             })
                                                         }
                                                     });


                                                 })
                                             })
                                 })

                                   




                                 })


                             })


                               .catch(function (e) {


                                   console.log(e.message);


                               })


                         }


                     })



                 })


             })


         })


         .catch(function (e) {


             console.log(e.message);


         })


     }

 

Resources

From August’s call

Office Add-ins community call

Office Add-ins feedback

The next Office Add-ins community call is on Wednesday, September 9, 2020 at 8:00AM PDT. You can download the calendar invite at https://aka.ms/officeaddinscommunitycall.

Engage with us
Are you interested in delivering a presentation during an upcoming Office Add-ins community call? Or would you be willing to provide feedback aimed at helping to improve the Office Add-ins documentation? If you answered yes to either (or both!) of these questions, please connect with us by completing this short survey form.

 

 

filter-icon