How Windows 10 virtual desktops help me with Office 365 development

In this article I will show how the Windows 10 virtual desktops help keep my brain organized for Office 365 development. It allows me to keep my Chrome Primary work profile for email etc completely separate from my developer tenat Chrome profile. It helps keep me more organized when working on multiple projects as well.

Background

Anyone who has more than one development and primary Office 365 account has come across the age old problem of which environment am I currently working in. Using Chrome profiles as a number of people have blogged about has been a huge help in this. Having a Chrome profile for dev tenant and profile for primary account (work email etc) is a huge help.

But the downside is many instances of chrome floating around and when you click on a link in Outlook it opens in the last Chrome window you were working on – which is frustrating at the best of times when your dev tenant says you dont have access to your primary email (duh) and then you have to hunt down the primary profile window and go back to outlook and start again.

Windows 10 Virtual Desktop

This is where the virtual desktop has really become my best friend for Office365 development. In the latest version of Windows 10 you can easily make a virtual desktop by adding the “Show Task View button” from the context menu when right clicking on the windows task bar.

Clicking on the Task icon brings up the option to create a new virtual desktop and also a view of some of things you have worked on recently.

Opening a new virtual desktop everything is blank and you can open Chrome and go to your dev chrome profile happily.

Switching between desktops

You can go through the process of Task View and clicking on the desktop you want

OR

You can use CTRL-WINDOWSKEY-Left/Right to navigate back and forth between the desktops. They don’t cycle but if you only have two then Left or Right isn’t that hard 🙂

Clicking a link in outlook

If I am working in desktop 2 (O365Dev) and I go back to Desktop 1(primary O365), clicking a link in the primary O365 Outlook opens the link in the primary desktop chrome profile. Always.

YAY 🙂

Mentally this also helps me keep my Director day job (primary O365) and dev environment (xomino365) separate and makes life easier.

It’s not for everyone but really helps me 🙂

Extra Bonus shortcut

I discovered by accident (as you do) that you can create a new Virtual desktop using the CTRL key and a three-finger down swipe on the laptop.

 

 

Create custom functions in Excel

As of MS Build 2018 custom functions in Excel are available for all developers to use and implement.

https://dev.office.com/blogs/azure-machine-learning-javascript-custom-functions-and-power-bi-custom-visuals-further-expand-developers-capabilities-with-excel

For more information on how to create a custom function in Excel using the JavaScript Add-In model check out this link.

https://aka.ms/customfunctions

“Custom functions (similar to user-defined functions, or UDFs), enable developers to add any JavaScript function to Excel using an add-in. Users can then access custom functions like any other native function in Excel (such as =SUM()).”

This is actually a huge deal because one of the limitations of the Add-In model in the past is this ability to create a custom function without having to add it to the tool bar as an icon which has to be clicked. With this release it means that develoipers can create their own functions in excel in an analogous manner to VBA. The simple example below adds the two numbers and for no good reason adds 42 as well. But you get the idea.

custom functions

 

 

 

Office Add-Ins: Working with Tables in Word. Part 1: Creation

In this article I will show how the Word JavaScript API can be utilized to add tables to your word document using an Office Add-In. This will be a multi part blog post as there are a lot of nuances and interesting ways in which you can play with tables in Word.

Introduction

In previous articles I have written about how to interact with a Word document to search and replace and even save the word document to Salesforce. Going back to a more basic level we are going to look at how to build tables in word.

We will be using the new Script Lab  which is a new Playground Add-In which can be used for development and general tinkering with Add-Ins. This and other articles on the topic are for demonstration purposes and are not hardened for production use.

The reference

For more information on Tables and how what methods/properties are available check out the documentation page – Table Object (JavaScript API for Word)

Creating a table 

At the most basic level a table is created by instantiating the table object and adding values to it.

insertTable(rowCount: number, columnCount: number, insertLocation: string, values: string[][])

This can be done from a number of different parents:

  • The body
  • A range
  • A contentControl
  • A paragraph

The method requires the following:

  • rowCount – a number
  • columnCount – a number
  • insertLocation – Depends on parent – either (body: Start/End/Replace) or (range: Before/After)
  • values: 2 dimentional Array – [[“This is”, “a table”], [“this is”, “a new row”]]

Using these parameters we can create a table from within the Script lab using the following code:

$("#run").click(run);

async function run() {
    try {
        await Word.run(async (context) => {

            var body = context.document.body;
            var range = context.document.getSelection();
            var myArray = [["a", "b"], ["c", "d"]];
            var table = range.insertTable(2, 2, "Before", myArray);            

            // Synchronize the document state by executing the queued commands,
            // and return a promise to indicate task completion.
                await context.sync().then(function () {
                    console.log('Table added before the start of the range.');
                });;
        });
    }
    catch (error) {
        OfficeHelpers.UI.notify(error);
        OfficeHelpers.Utilities.log(error);
    }
}

 

 

Conclusion

Using the Script Lab we have seen how we can easily insert a table into a Word document using the Office Add-In API. In future articles we will look at looking for the table we want to modify and then manipulating tables.

 

 

Building Office Add-ins using Office.js – the book, the website

I wanted to show some love for the new website and book by Michael Zlatkovsky. Michael is a Software Developer and Program Manager in the Microsoft Office Extensibility team. I met Michael at the MS MVP Summit back in October and we had a great conversation or two about Office Addins and their future development.

So Michael’s new leanpub book is called Building Office Add-Ins using Office.js and can be purchased through leanpub. The new supporting website http://buildingofficeaddins.com/ provides some of the key information from the book and gives a nice overview thereof while introducing the reader to the more technical aspects of using Office.js.

Michael’s a great guy and this is a very valuable resource for Office Add-In developers. I heartily recommend it.

SharePoint now accessible via the Microsoft Graph beta

Last week at Ignite it was announced that finally Microsoft was bringing O365 SharePoint access to the Microsoft graph as an API. This is a huge deal for those of us who want to use O365 as a platform and develop engaging applications for customers. In my case for Office Add-ins this is great because it reduced the number of OAuth hoops I have to jump through and manage to get the data I want.

Here is a link to the documentation: Working with SharePoint sites in Microsoft Graph and a quick example.

NOTE: this is beta and will change – this is purely a demonstration of what is possible today (Oct 2016) and not to be used as future reference.

Example

Using the graph explorer demo I am able to bring up content from my default SharePoint site very easily

https://graph.microsoft.io/en-us/graph-explorer#

Here is my copper site within my SharePoint tenant

sh1

and here it is referenced from the graph API

https://graph.microsoft.com/beta/sharepoint/sites/site-id

sh2

here is the API response of the lists
https://graph.microsoft.com/beta/sharepoint/sites/site-id/lists

sh3

and here is a reference to the documents in the Shared Documents folder

https://graph.microsoft.com/beta/sharepoint/sites/site-id/lists/list-id/items

sh4

How cool is that !!!!!

 

Saving a word document directly from an Office Add-In into Salesforce.com

In this article I will demonstrate and discuss how to programmatically save a Word document directly into Salesforce.

Introduction

In previous articles we have looked at how to programmatically interact with a Word document from within an Office Add-In. In this case we will use the Office JavaScript API to access the file as a binary string and then convert it into a format compatible with Salesforce.com.

Turning your word document into a binary

This article in the Office dev center details how to Get the whole document from an add-in for PowerPoint or Word. We will use the bulk of that article up to the point where we send the slice. We are going to look at a modified sendSlice() function. The dev.office.com article details how you can access the binary contents of the word document, but falls short when it comes to getting the base64 encoded version of the file to be submitted to an external site. This is the complicated part !

Getting the right format for Salesforce

Unfortunately the salesforce documentation is not based around using JavaScript to access the REST APIs. It is based around using curl commands in UNIX. The sample page for Inserting or updating Blob Data explains how to upload a multipart message which includes both the meta-data values and the binary data for the file. For the record they also neglect to provide any guidance on how to get the binary of the file….!

Using the code posted on this stackoverflow post  we are able to turn a binary string into the necessary format to send the file to salesforce.

The final sendSlice() function is shown below. The significant thing to note is that the initial file must be sent to the ContentVersion sobject. Because this is a new document a parentId is not necessary and a ContentDocumentId is created. In a future article we will look at how to then associate this new file attachment is an existing object.

function sendSlice(slice, state) {
  updateStatus("In sendSlice");
  var data = slice.data;

  // If the slice contains data, create an HTTP request.
  if (data) {

    // Encode the slice data, a byte array, as a Base64 string.
    // NOTE: The implementation of myEncodeBase64(input) function isn't
    // included with this example. For information about Base64 encoding with
    // JavaScript, see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Base64_encoding_and_decoding.

    var u8 = new Uint8Array(data);
    var b64encoded = btoa(String.fromCharCode.apply(null, u8));

    var objectData = {
      "Description": "Demo Upload Directly from Word",
      "Title": "sample.docx",
      "ReasonForChange": "Initial Upload",
      "PathOnClient": "sample.docx"
    }

    var boundary = 'boundary_string_' + Date.now().toString();
    var attachmentContentType = 'application/octet-stream';

    // Serialize the object, excluding the body, which will be placed in the second partition of the multipart/form-data request
    var serializedObject = JSON.stringify(objectData);

    var requestBodyBeginning = '--' + boundary
        + '\r\n'
        + 'Content-Disposition: form-data; name="entity_attachment";'
        + '\r\n'
        + 'Content-Type: application/json'
        + '\r\n\r\n'
        + serializedObject
        + '\r\n\r\n' +
        '--' + boundary
        + '\r\n'
        + 'Content-Type: ' + attachmentContentType
        + '\r\n'
        + 'Content-Disposition: form-data; name="VersionData"; filename="filler"'
        + '\r\n\r\n';

    var requestBodyEnd =
        '\r\n\r\n'
        + '--' + boundary + '--';

    // The atob function will decode a base64-encoded string into a new string with a character for each byte of the binary data.
    var byteCharacters = window.atob(b64encoded);

    // Each character's code point (charCode) will be the value of the byte.
    // We can create an array of byte values by applying .charCodeAt for each character in the string.
    var byteNumbers = new Array(byteCharacters.length);

    for (var i = 0; i < byteCharacters.length; i++) {
      byteNumbers[i] = byteCharacters.charCodeAt(i);
    }

    // Convert into a real typed byte array. (Represents an array of 8-bit unsigned integers)
    var byteArray = new Uint8Array(byteNumbers);

    var totalRequestSize = requestBodyBeginning.length + byteArray.byteLength + requestBodyEnd.length;

    var uint8array = new Uint8Array(totalRequestSize);
    var i;

    // Append the beginning of the request
    for (i = 0; i < requestBodyBeginning.length; i++) {
      uint8array[i] = requestBodyBeginning.charCodeAt(i) & 0xff;
    }

    // Append the binary attachment
    for (var j = 0; j < byteArray.byteLength; i++, j++) {
      uint8array[i] = byteArray[j];
    }

    // Append the end of the request
    for (var j = 0; j < requestBodyEnd.length; i++, j++) {
      uint8array[i] = requestBodyEnd.charCodeAt(j) & 0xff;
    }

    //Create the new file in Salesforce
    var url = "https://yourdomain.my.salesforce.com/services/data/v37.0/sobjects/ContentVersion/"

    return $.ajax({
      method: "POST",
      url: url,
      processData: false,
      data: uint8array.buffer,
      headers: {
        "Content-Type": 'multipart/form-data' + "; boundary=\"" + boundary + "\"",
        "Authorization": "Bearer " + app.getCookie(app.addinName)
      }
    }).error(function (data) {
      updateStatus("FAIL: " + JSON.stringify(data))
    }).success(function (data) {
      updateStatus("Success creating ContentVersion: " + data.id)
      closeFile(state)
    });

  }
}

 

Conclusion

In this article we have seen an example of how we can extend the functionality of an Office Add-In to access the binary data of a word document and then save it to a cloud provider (in this case Salesforce).

 

Speaking at SharePointFest Chicago 2016

I am very excited to announce that I have been accepted to speak at SharePointFest, December 8th 2016 in Chicago.

http://www.sharepointfest.com/~spfadmin/Chicago/index.php/sessions/38-sharepoint-development/118-dev103-office-365-add-ins-a-web-developer-s-playground

Title 
DEV 103 – Office 365 Add-Ins: A web developer’s playground

Abstract
Like most office workers, we all spend a significant amount of time in our “Microsoft Office” productivity tools. Even email is still a productivity tool. Productivity starts to diminish though if we have to move outside of our Office environment and hunt for information and/or complete business workflow processes.

With the creation of Office 365 Add-Ins, Microsoft has presented web developers with a new opportunity to create rich, engaging and integrated user experiences without having to leave the “experience” of our Office applications. Developers have the ability to create Add-Ins using HTML/JS/CSS and these run in the Windows Client, on the web, on our phones and even on the OS X desktop client.

In this presentation Mark will provide lots of demonstrations of how to get started with Office Add-Ins. These will include: creating your first Add-In in under 2 minutes, how to simplify workflow approval without having to leave your email client, how to pull report and analytics data into your Office product suite applications, integrating SharePoint as a Service, integration with Salesforce and how to integrate your content with cognitive analytics.

Come to the presentation and find out why Office 365 Add-Ins are a modern web developers playground.