Blisk – a web developer’s browser – first impressions

On the twitternet last Friday afternoon I saw this thing called “Blisk – a web developer’s dream come true” and frankly that sounds like fun !

http://mashable.com/2016/05/13/blisk-web-browser

and that lead me to “https://blisk.io/“. This is a record of my first interaction with it and see how it goes. This is not a review – this is just a record of OOOO shiney in action !!

Installation

I downloaded it – I am not entirely sure that is asked me if I wanted do anything after I ran the installer…..Windows only right now apparently.

Start up

I loaded it up and started to type in the addressbar and it already knew my Chrome browser history 😱

b1

 

A nice handy start screen shows me the rapidly approaching features…

b2

b2 b3 b4 b5 b6 b7 b8 b9 b10

Loading up a responsive website

I loaded up one of my demo sites and was able to display it Real site, side by side with mobile iPhone

bb1

and  iPad

bb2

can’t figure out how to make the mobile device change orientation though yet….

Using a watcher.

I loaded up a simple Local node server and displayed a simple page. I then added a watcher to the page like this:

bb3

and this is the result – SO COOL !!!

 

Because it is chrome (I mean webkit) and because I can, I was poking around and I discovered that the watcher functionality has actually been installed as a built in chrome extension – chrome.tabs.watcher. Very nicely done guys !!!

So that’s about it so far – needless to say I am going to be watching this one very intently – even if this doesn’t work out, it will certainly kickstart the imagination of others – bravo !

More features coming

Seems like there is more to come – I am going to enjoy watching this evolve 🙂

bb4

And even More to come

Featured the developers say are “coming soon” on their website are:

  • Integrations with Jira, Pivotal tracker and other productivity tools
Advertisements

Programmatically Inserting an image from an O365 Add-In into your Word 2016 document

In this article I will demonstrate how to convert a web based image, displayed in an Add-In, into a base64 encoded string. With that I will then insert it into a Word document, directly from the Add-In.

Introduction

In the previous article I showed how to manually insertInlinePictureFromBase64 an image into a Word 2016 document. In this article I will demonstrate how to convert and existing web based image into base64 encoded string and then insert it.

HTML5 canvas element

Using the HTML5 canvas element we can easily convert an image to base64 using the canvas.toDataURL() method. The following code is a simple example of how to get an image from within the Add-In, convert it and insert it.

NOTE

The canvas.toDataURL() method will trigger a Security Alert if the image is not hosted in the same domain as the Add-In.

//create a canvas element 
var c = document.createElement("canvas"); 
var ctx = c.getContext("2d"); 
var img = document.getElementById("preview"); 
ctx.drawImage(img, 10, 10); 
//create the base64 encoded string and take everything after the comma
//format is normally data:Content-Type;base64,TheStringWeActuallyNeed
var base64 = c.toDataURL().split(",")[1];

//insert the TEXT o fthe base64 string into the word document as text
// Run a batch operation against the Word object model.
Word.run(function (context) {

    // Create a proxy object for the document body.
    var body = context.document.body;

    // Queue a commmand to insert HTML in to the beginning of the body.
    body.insertHtml(base64, Word.InsertLocation.start);

    // Synchronize the document state by executing the queued commands,
    // and return a promise to indicate task completion.
    return context.sync().then(function () {
        console.log('HTML added to the beginning of the document body.');
    });
})
.catch(function (error) {
    console.log('Error: ' + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
        console.log('Debug info: ' + JSON.stringify(error.debugInfo));
    }
});

//Insert the image into the word document as an image created from base64 encoded string
Word.run(function (context) {

    // Create a proxy object for the document body.
    var body = context.document.body;

    // Queue a command to insert the image.
    body.insertInlinePictureFromBase64(base64, 'Start');

    // Synchronize the document state by executing the queued commands,
    // and return a promise to indicate task completion.
    return context.sync().then(function () {
        app.showNotification('Image inserted successfully.');
    });
})
.catch(function (error) {
    app.showNotification("Error: " + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
        app.showNotification("Debug info: " + JSON.stringify(error.debugInfo));
    }
});

As we can see from the image below – the image and text are inserted. There is 4 pages of text for what was originally a 6KB (SIX) image.
This is not a very quick process.

im1

im2

Conclusion

This is pretty slow programmatically and a copy and paste is just as effective. But, it can be done so you never know someone might find use for it in the future 🙂

Inserting a base64 encoded image into a Word 2016 document

In this article I will demonstrate the new Word JavaScript API method which can be used to insert a base64 encoded image into a Word 2016 document.

Introduction

In the latest version of Office 365 Word 2016 (May 2016) a new capability has been released “insertInlinePictureFromBase64”. The documentation so far is a little sparse but can be found here (http://dev.office.com/reference/add-ins/word/body) . The new method is part of the body object within the JavaScript API model. For more information on the version of Word you need to get this to work check out this link (Office add-in requirement sets).

Do you have the correct version?

I found this StackOverflow answer which gave code similar to the following to test to see if you have the correct version of the JavaScript API available.

Word.run(function (context) {
	// Create a proxy object for the document body.
	var body = context.document.body;
	// Queue a commmand to insert HTML in to the beginning of the body.
	if (Office.context.requirements.isSetSupported("WordApi", "1.2")) {
		body.insertHtml('<strong>"You have the right version"</strong>', Word.InsertLocation.start);
	} else {
	body.insertHtml('<strong>"You do not have the right version. This functionality requires Word with at least January 2016 update!! (check  builds 6568+)"</strong>', Word.InsertLocation.start);
	}
		// Synchronize the document state by executing the queued commands,
		// and return a promise to indicate task completion.
		return context.sync().then(function () {
			console.log('HTML added to the beginning of the document body.');
	});
})

I created a simple Add-In examples locally, containing a message DIV and some FirebugLite.

Inserting an image.

Taking one of the examples from the documentation page and modifying it slightly we can see the basics of how the insert will happen:

var img = '' //a base64 encoded string

// Run a batch operation against the Word object model.
Word.run(function (context) {

    // Create a proxy object for the document body.
    var body = context.document.body;

    // Queue a command to insert the image.
    body.insertInlinePictureFromBase64(img, 'End');

    // Synchronize the document state by executing the queued commands,
    // and return a promise to indicate task completion.
    return context.sync().then(function () {
        app.showNotification('Image inserted successfully.');
    });
})
.catch(function (error) {
    app.showNotification("Error: " + JSON.stringify(error));
    if (error instanceof OfficeExtension.Error) {
        app.showNotification("Debug info: " + JSON.stringify(error.debugInfo));
    }
});

As we can see from the code, what is happening is the the “context” of the Word document is being manipulated in memory and then “sync’ed” with the actual HTML managing the Word document. The “Word document” itself is not a webpage. It can handle HTML but it is not a web browser and is not capable of being manipulated directly from the Add-In. If this works we should see an image.

What is a base64 encoded string anyway?

Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation. The term Base64 originates from a specific MIME content transfer encoding.” (https://en.wikipedia.org/wiki/Base64)

If you look for examples of base64 encoded images on the web you can see something like this – https://css-tricks.com/examples/DataURIs/ which shows two ways of referencing an image using the encoded string. Firstly in CSS and secondarily as an image. View the source of the page

i2

i1

The “base64 encoded string” takes the form “data:”+ [content-type]+”;base64,” and then the actual string

data:image/gif;base64,R0lGODlhEAAQA……………

“data:”+”image/gif”+”;base64,”R0lGODlhEAAQA……………….”

I am not using the full string for the base64 encoded image in my code snippets, because it is unwieldy in the context of the blog post.

THIS IS THE REALLY IMPORTANT PART !!!!
In the case of insertInlinePictureFromBase64 the entire string does not work! You only use everything after the comma.
THIS IS THE REALLY IMPORTANT PART !!!!

In my case only the following is necessary

var img = ‘R0lGODlhEAAQA……

In Summary

As you can see from the image below when you put this all together inside your JavaScript you can insert images into your Word document..

i3

Using the Jellyfish image example (which is a really long text string)

i4

 

Conclusion

In this article we seen how the new body.insertInlinePictureFromBase64 method can be used with the Word API to insert an image into a word document. Particular attention has to be paid to the string being inserted for the image, it must not include the content-type or the data signifier.

In the next article we will look at how we can easily a base64 encoded image for ourselves programmatically in the context of an Add-In

 

 

Speaking at the Collab365 Summit 2016 – May 11th 2016 – “Office 365 Add-Ins – a web developer’s playground”

I delighted to say that at very short notice, I am speaking at the Collab365 Summit virtual conference on May 11th 2016.

https://collab365.events/collab365-summit-2016/

The presentation will be recorded and there will be a live chat session while it is being broadcast

Monday May 11th 12pm CST

co1

Title
Office 365 Add-Ins – a web developer’s playground

Abstract
A web developer’s exploration into the capabilities and integration opportunities exposed by O365 and the Office Add-In model. 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 and how to integrate your content with cognitive analytics. All of this, written without a single line of C#.

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

Office 365 Add-Ins Dialog API released

In this article I will briefly touch on the new Dialog API, the fact that it works in Outlook and that you need to have the most recent version of Office 2016 to get this to work.

Introduction

In his recent article Simon Jaeger published information about the new Office 365 API “DialogAPI” functionality

http://simonjaeger.com/lets-have-a-dialog-about-the-dialog-api/

This is a really nice UX item added to the Office 365 Add-In suite of functionality. If I need to ask the user to interact with the application and/or make a decision, it is now available right there from within the Add-In.

Not just for Word

While Simon’s example was created in Word, using the following code it was really simple to test and see if it was available in Outlook as well.

It is !!

d1

I used my firebuglite Add-In example to quickly load up an existing Add-In and paste the code into the console window. Took 2 minutes to verify which was great.

        var dialogUrl = location.href

        // Display the dialog.
        Office.context.ui.displayDialogAsync(dialogUrl, { width: 15, height: 27, requireHTTPS: true }, function (asyncResult) {
            if (asyncResult.status !== Office.AsyncResultStatus.Succeeded) {
                // TODO: Handle error.
                return;
            }

            // Get the dialog and register event handlers.
            var dialog = asyncResult.value;
            dialog.addEventHandler(Microsoft.Office.WebExtension.EventType.DialogMessageReceived, function (asyncResult) {
                if (asyncResult.type !== Microsoft.Office.WebExtension.EventType.DialogMessageReceived) {
                    // TODO: Handle unknown message.
                    return;
                }

                // Parse the message.
                var data = JSON.parse(asyncResult.message);
                showNotification('Hello #Office365Dev', data.name);

                // TODO: Do something with the data.

                // We got our data, time to close the dialog.
                dialog.close();
            });
        });

In Simon’s post he also referenced the Channel 9 video created to go along with the announcement. In that the presenters demo how to use the new dialog API to Authenticate to O365 and return the token back to the Add-In. This is a more elegant method than what I have been using with the whole new IE window opening. I will be looking into combining the methods for my own nefarious use in the near future….. 🙂

Office Version (April 2016)

I wasted over a day being frustrated with why my code would not worked, and it turns out that my version of Office was not up to date. You need to go to the following site to download the latest version of Office (https://github.com/OfficeDev/Office-Add-in-Commands-Samples/blob/master/Tools/LatestOfficeBuild.md).

 

Conclusion

The new Dialog API presents a new option for developers in their continued ability to bring functionality into the Office 365 environment.

 

Creating an O365 Authorization Token via Chrome Extension

In this article I will show how I extended my method for generating an O365 OAuth token and incorporated it into a chrome extension.

Introduction

When I created the O365Token project on GitHub it was for the express purpose of being able to generate an OAuth token for an O365 Add-In project. I have since been tasked with integrating O365 into an application via a Chrome Extension. Using the same methodolgy it turned out to be relatively simple to do.

Creating a Chrome Extension

There is an extensive API for creating Chrome extensions which allows us to execute JavaScript at run time for a given website. What is particularly useful is that we are able to execute different scripts based on the site being accessed.

The basic extension

I created a extension locally with nothing more than the basic inclusion of a manifest and a JavaScript hello world.

g1

The background.js file is very simple

$(document).ready(function() {
    console.log('hello world');
})

and when I visit an https://xomino365.com site I see the extension log in the console.

g2

Adding O365Token to the extension

In the github project we have two files, Home.js and App.js. These two files are added to the chrome extension and the folder structure.

The Home.js file is modified with the necessary parameters for generating the OAuthToken as described in this previous article. I also modified the replyURL as in this case it is not an Office Add-In.

g3

You will also notice that I changed the first few lines of code to remove the call to Office.js.

Executing the Chrome extension

Once the code has been implemented, I go to a https://xomino365.com webpage and I am immediately prompted with a new window requesting O365 Authentication.

g4

g5

Once I authenticate, an OAuthToken is created and set as a cookie within the xomino365.com domain. Using this I can then add O365 application data into my xomino365.com website seamlessly.

I

Because of the ability to “match” the website which this occurs in, within my extension, this functionality will only appear on this website.

Updating the O365Token Github

I have updated the O365Token Github site with the Chrome extension as a separate folder within the repository. Please feel free to try it out for yourself with your own O365 sites.

 

Conclusion

In this article we have seen how a simple Chrome Extension is constructed and how we can add O365 Authorization capabilities to it.

The ability to easily integrate O365 through a Chrome Extension opens up the future possibility for integration between existing applications and O365 through the use of DOM insertion. More on this in a later article.

Corporate Tools to come…..

What is intriguing to me is that unless you’re using corporate GMail, Chrome itself is not normally a “default browser” inside a company using O365. More likely of interest to corporate world is that Microsoft Edge Extensions are coming (as of April 2016) and they are supposedly going to be very similar to Chrome extensions. This could very well have a lot more developer leverage in that environment. I guess I need to get on that train and find out……

 

 

Getting attachments from an O365 SharePoint list item Cross-Domain

In this article I will demonstrate the nuances of being able to get Office 365 SharePoint attachments in the same domain and in the Cross-Domain scenarios.

Getting information about a list item

When requesting information from a list in SharePoint, the detail returned does not by default contain any information about attachments other than “yep I got some”. The image below shows a typical response from a simple request to show the first value in the list

var path = "https://psclistensdev.sharepoint.com/sites/demo/";
$.ajax({
  url: path+"_api/web/lists/GetByTitle('Company')/Items?$top=1",
  type: "GET",
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer " +  app.getCookie("OAuthToken")
  },
  contentType: "application/json;odata=verbose"
}).done(function(res){
    console.log(res)
})

s1

To be able to see information about the Attachments we add the $expand=AttachmentFiles parameter to the URL

var path = "https://psclistensdev.sharepoint.com/sites/demo/";
$.ajax({
  url: path+"_api/web/lists/GetByTitle('Company')/Items?$expand=AttachmentFiles&$top=1",
  type: "GET",
  headers: {
    "Accept": "application/json",
    "Authorization": "Bearer " +  app.getCookie("OAuthToken")
  },
  contentType: "application/json;odata=verbose"
}).done(function(res){
    console.log(res)
})

s2

Looking at the Attachment information

There are multiple URLs which are returned in the JSON – looking at each of them we find that some open/download the file

  1. //psclistensdev.sharepoint.com/sites/demo/Lists/Company/Attachments/1/quickstart_guide.pdf
    • works great file downloads
  2. //psclistensdev.sharepoint.com/sites/demo/_api/Web/Lists(guid’eaf7c922-649e-4447-b695-df9030e85072′)/Items(1)/AttachmentFiles(‘quickstart_guide.pdf’)
    • Creates a file called “AttachmentFiles(‘quickstart_guide.pdf’)” which when opened in notepad is actually an XML reference document…

So when downloading the file attachment in the same domain – requesting the file via the first URL – works just fine

s3

But if we move to a different domain (which has previously been added as a trusted App through Azure AD) we find that the Cross Domain headers are not provided and therefore the download fails…..

s7

I believe (although I cannot be sure) that this is because the direct URL for the attachment does not use the “_api” it is not being picked up by the Azure AD App permission process and the headers are not being added.

Doing it the other way

Going back to URL #2 (which if you remember returns an XML file)

  • //psclistensdev.sharepoint.com/sites/demo/_api/Web/Lists(guid’eaf7c922-649e-4447-b695-df9030e85072′)/Items(1)/AttachmentFiles(‘quickstart_guide.pdf’)

If we try to request this, it does actually work…..but returns the JSON version of the XML file (cos I asked it to in the headers)

s5

The trick here is to add “$value” to the end of the URL. This triggers SharePoint to send out the attachment itself

  • //psclistensdev.sharepoint.com/sites/demo/_api/Web/Lists(guid’eaf7c922-649e-4447-b695-df9030e85072′)/Items(1)/AttachmentFiles(‘quickstart_guide.pdf’)/$value

s6

Conclusion

In this article we have seen how there are multiple ways to collect the reference to a file attachment from a list item in O365 SharePoint. While both URLs work when requested from the same domain, only one of them triggers the Azure AD App registration model to add the appropriate HTTP Headers to the request, allowing a Cross-Domain request to be successfully executed.