Documentation, documentation, documentation…

I have published working documentation in GitHub for OfficeJS.dialogswlEmoticon-hotsmile.png

If you click that link, you will see the README.md at the bottom of the repository has all the usage details, some sample code and example images of each dialog type supported in the library. But, you can also see a prettier version here:

https://davecra.github.io/OfficeJS.dialogs/

I have never used GitHub for documentation before. It uses a format called Markdown. It is actually very easy to learn and use. I spent about 3 hours and knocked out that document you see and it has:

  • Linked images from this blog
  • A Table of Contents with hyperlinks to different sections
  • Inline hyperlinks to different places in the documentation
  • A sorts of formatting including Headings.

Anyway, as I was building that documentation, I found a few minor bugs – and actually one really big one. I will likely be posting v1.0.6 pretty soon.

The big one: If you try to use the CDN for OfficeJS.dialogs, you will not see anything. The reason is that the HTML page that I use is not in “your” domain. For the Office.context.ui.displayDialogAsync() method to work, the URL to show the INITIAL file, needs to be from the same domain as your code. I totally face palmed wlEmoticon-confusedsmile.png on this one. So, I am going to provide a method:

OfficeJS.dialogs.Initialize(url);

You will call this first if you will be using the CDN. The URL will be an HTML page on your site that has some specific JavaScript (I will provide) to initially load your page, but then update with the OfficeJS.dialogs.html from the CDN. Or, at least that is the idea.

In the meantime, I suggest using NPM to install locally to your solution as per my blog post here:

npm load officejs.dialogs

OfficeJS.dialogs Updated (v1.0.5)

I have been working hard on my OfficeJS.Dialogs library and just published version 1.0.5. You can get it from NPM and GitHub. See my previous post for more information on how to do this.

I have added a few new features:

  • A simple Alert.Show() method that displays a simple OK box. For those times you want to just simply pop up a quick notification to the user.
  • A Progress.Show() that displays a progress bar. This allows for you to show the progress bar and then issue Progress.Update() to move the progress bar along. When you are done you call Progress.Complete().
  • A Wait.Show() dialog that will show an indeterminate spinner. This form will remain up until you issue a Wait.CloseDialog().
  • New UpdateMessage() and Update() methods were added to the MessageBox. This was done to allow you to quickly ask a lot of questions of the user in one instance of the dialog, without giving the user back to the application for a second while the new dialog is rendered. UpdateMessage() will just update the message but keep all the buttons the same, but you will specify a new callback. Update() will allow you to fundamentally change all the settings the MessageBox (buttons, icon, caption, text and all), plus a new callback function.
  • Behind the scenes I made some improvements/bug fixes:
    • If you try to show two dialogs too quickly, nothing will happen. So I added a half-second delay between dialog displays to make sure you never get an overlap.
    • You will get an error message in your callback if more than one dialog is attempted to be opened at once.
    • “Window Messaging” has been setup with Progress and MessageBox to allow the parent and the dialog to pass messages back and forth. It involves using setTimeout().

For those interested in the last item, here is what that look like:

        /**
        * Handles messages coming from the parent
        */
        function startMessageHandler() {
            setTimeout(function() {
                var message = localStorage.getItem("dialogMessage");
                localStorage.setItem("dialogMessage", ""); // clear the message
                if(message !== undefined && message !== null && message != "")
                {
                    var msg = JSON.parse(message);
                    if(msg.message == "update") {
                        // update the form
                        updateForm(msg.settings);
                    } else if(msg.message == "close") {
                        // do nothing special here
                        return; // stops the message pump
                    } else if(msg.message == "progress") {
                        if(msg.settings.Number > 100) return;
                        $("#bar").prop("value",msg.settings.Number);
                    }
                }
                startMessageHandler(); // call again
            }, 0);
        }

Here is an example of how to use the Progress dialog. The method signature is like this:

Progress.Show( [message], [start], [max], [completeCallback], [cancelCallback] )

  • The message is the message the user see’s when the dialog is opened.
  • The start is the number you want the progress bar to start at. Usually this should just be zero (0).
  • The max is the number you want the Progress bar to end at. Usually this should be 100. But it can be any number you want. If you have 5 steps to perform in the background while this dialog is up, you can set this to 5.
  • The completeCallback is your callback function to be called when your code calls the Progress.Compelte().
  • The cancelCallback is what gets called when the user presses the Cancel button on the form.

By itself, this will do nothing. You will have to call the Progress.Update() command in order to move the progress bar, or update the message to the user. Here is the method signature for the Update method:

Progress.Update( [amount], [message] )

  • The amount is how much you want the progress bar to move. If you do not specify an amount, an amount of 1 is assumed.
  • The message is a new message to provide the progress bar. If you want to update the message and do not want to increment the progress bar, specify an amount of zero (0).

Once you are all done with the Progress dialog, you issue a Progress.Complete() call. There are no parameters to it. Once called, your completeCallback in the Progress.Show() call will then be executed.

Here is an example:

// reset first to make sure we get a fresh object
Progress.Reset();
// display a progress bar form and set it from 0 to 100
Progress.Show("Please wait while this happens...", 0, 100, function() {
    // once we are done - when your code
    // calls Progress.Complete()
    Alert.Show("All done folks!");
  }, function() {
    // this is only going to be called if the user cancels
    Alert.Show("The user cancelled");
});
doProgress();

function doProgress() {
  // increment by one, the result that comes back is
  // two pieces of information: Cancelled and Value
  var result = Progress.Update(1);
  // if we are not cancelled and the value is not 100%
  // we will keep going, but in your code you will
  // likely just be incrementing and making sure
  // at each stage that the user has not cancelled
  if(!result.Cancelled && result.Value <= 100) {     setTimeout(function() {       // this is only for our example to       // cause the progress bar to move       doProgress();     },100);   } else if(result.Value >= 100) {
    Progress.Compelte(); // done
  }
};

That example also uses the new Alert dialog. This one is very simple:

Alert.Show ( [message] )

This next example uses the new Wait dialog, which is much simpler to implement. Here is the method signature:

Wait.Show( [message], [showCancel], [cancelCallback] )

  • The message is the message you want to show the user. If you specify null, it will appear as simply “Please wait…”
  • The showCancel flag if set will allow the user to see a Cancel button.
  • The cancelCallback function is only valid if the showCancel option is true. When the user presses cancel, this function gets called.

When you are ready to close the Wait dialog, you issues a Wait.CloseDialog(). Here is an example:

  Wait.Show(null, true, function() {
    Alert.Show("The user cancelled.");
  });
  setTimeout(function(){
    Wait.CloseDialog();
    Alert.Show("Done!");
  }, 15000);

If you have some suggestions for some things you would like to see added to this library, please add a comment below or reach out to me on LinkedIn or Twitter. Some ideas I will be working on:

  • Allow you to call another dialog type without having the close the dialog.
  • A selection dialog, where you have a dropdown list of a listbox where you wan select (or multi-select) items.
  • An option to resize forms.
  • An option to use the message handler in your own custom form – minimal code

VSCode: error TS5042: Option ‘project’ cannot be mixed with source files on a command line.

I have been using VSCode a lot lately. I have recently started delving into TypeScript and wanted to use VSCode to begin developing my first project. I was following a tutorial on Lynda.com and for the life of me could not get it to “transpile” my TS project. I setup everything according to this site and it failed. What I kept getting was this error:

error TS5042: Option ‘project’ cannot be mixed with source files on a command line.

This error is all over the web and not a single solution helped. I am guessing it is caused by the fact I have VS2015, VS2017, and VSCode installed on my box. But, this is the weird thing, if I go to the PowerShell in the Terminal window and paste the EXACT command that VSCode uses… IT WORKS!!! What? I started puling my hair out at this point…

Ok, now that really sucked. So, I got fed up and just build my own tasks.json using the “Other” option and here is what I entered:

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "taskName": "DaveCra TSC Task for VSCode",
            "command": "tsc -p tsconfig.json",
            "type": "shell",
            "problemMatcher": [
                "$tsc"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ]
}

Once I set this up, it was the default build task and a CTRL+SHIFT+B ran fine. Right after that I was able to go to the PowerShell terminal and type “node ” and it ran like a charm. wlEmoticon-hotsmile.png

Goodbye ModNotebooks, Hello OfficeLens

I like taking notes, the old fashioned way (by hand in a notebook, on… paper), but I like finding them the new way (using search on my PC). I love OneNote and how easy it is to keep an online notebook with all sorts of data. For example, due to archival rules some of my email starts to “disappear” from my work account after a couple of years. But some emails I like to keep – little nuggets of wisdom, notices, personal information and such I like to keep around. So, I export them to OneNote, where I can keep them safe.

So, I was living this duplicitous life of daily note taking with pen and paper but also filling my online notebook with all sort of information. I wanted to find a way to bridge these two. A few years back I was at a Microsoft convention and ran into a member of the OneNote team that turned me on to a small startup firm called: ModNotebooks. Their website is now gone, this is all you see:

mod.PNG

What they did was to send you a very high quality notebook, you would fill it up and ship it off to them. In the back of the notebook was a folder with a mail pouch and prepaid postage. They would receive it, scan it in for you and then dump the contents into your OneNote file behind the scenes. I filled 7 notebooks with them. But alas, their business model did not work, I am guessing, and they have gone out of business.

Now, I am left with my seeming duplicity again. wlEmoticon-disappointedsmile.png How do I get back to having my handwritten notes in OneNote again? Enter, OfficeLens.

I have actually been using this app for some time to scan travel receipts to PDF to turn in for expense reimbursement. And while I have always known I can use it for OneNote notes, I never tried it – namely because I had a better thing in ModNotebooks – or so I thought. Being forced to use something is sometimes what it takes. So, I gave OfficeLens a shot.

First, you download it to your phone. It comes on all three platforms (Windows Phone, iOS, and Android). Next, you hook up your Microsoft account (Live/Hotmail/MSN) and then you start scanning. It automatically finds the page and draws a border around it:

20170717_145127000_iOS.png

When you click the button at the bottom, it shows you what it got:

20170717_143239000_iOS.png

In the lower left, you can click the (+1), to add more page (up to 10 at a time – my only complaint – more on that later)* Once complete with your scanning, you click Done at the top right. This will take you to the “Export To” page.

20170717_143248000_iOS.png

From here I select OneNote and it asks me where I want to put it in my Notebook and when I click Save, it begins to upload it to my OneNote notebook:

And once it is in OneNote, it is fully text searchable, based on my handwriting. Yes, I said “fully text searchable” from my handwriting. Here is what it looks like once it gets to the final destination and I perform a search:

OneNote.PNG

Amazing, eh?

So, my only complaint is that the tool only allows you to scan in 10 pages at once. I wish there was a way to override this, for two reasons:

  1. I take a lot of notes and I fill 10 pages quickly. I have to get into the habit of scanning every week at this point to keep up. It is not impossible, but it would be nice to skip a few weeks and then scan them all in – in bulk. Right now, I have to upload it in several different batches of 10.
  2. I recently was working with legal documents and needed to print them out, sign them, scan them in and then send them off. The document had 11 pages. 11. 11! So, I had to scan 10 pages, then scan the last one and then find PDF merge software to merge them all together. That was NOT fun.

With that said, Au Revoir ModNotebooks. You were great while you lasted. I will likely be going back to using Moleskin’s and then using OfficeLens to digitize. We shall see… TUL (the “u” is long, so “tool”) has some nice notebooks too – I love their fine-point pen:

20170717_152827116_iOS

If you have any suggestions, please leave comments below. wlEmoticon-hotsmile.png

Going back to taking notes by hand…

 

Delay Loading Outlook Add-ins

A customer I work with encountered an issue where a specific add-in was causing Outlook to lose its network connection. Essentially, we were unable to get the “Click here to view more on Microsoft Exchange” (in cached mode) to light up. Here is what we saw:

connect error

Here is what we wanted to see:

connected

It was always grayed out and no mater what we did in Outlook with the connection state, it never same back.

After a lot of troubleshooting we found one particular in-house add-in was causing the problem. Oddly, everything worked great with the same add-in in previous versions of Outlook, but in Outlook 2016, we started seeing this problem. Therefore, we knew it had to be a change made in Outlook 2016. What we found is that Outlook 2016 had been greatly reconfigured in the startup code to optimize network connections as it now connects to the cloud (Office 365). So we started working with the product team on identifying the root cause and in the end we were unable to find a solution (in time). My customers deployment was delayed.

As such, I had to come up with a workaround. We found that if the add-in was not loaded when Outlook started, but was manually enabled after Outlook  launched, the problem would NOT occur. This got me thinking: What if I created an add-in that loaded add-ins AFTER Outlook was done loading all other add-ins?

The Outlook Delayed Loading of Add-ins for the Enterprise was born. By the way, that name is credited to my customer. The catchy acronym stuck: D-LAME Add-in. wlEmoticon-disappointedsmile.png

I have posted the project for it here on GitHub here:

https://github.com/davecra/DLAME

You will need to load it into Visual Studio and compile it and then sign it with a certificate on your own. The code is provided AS IS. The README.md on the page explains the installation, configuration and usage of the a add-in once you have it ready for deployment. Some key points:

  • You will want to make sure it is not disabled by setting the Resilience policy key for the add-in.
  • You will want to move the add-in(s) you wish to delay from HKLM to HKCU registry locations.
  • You can load DLAME as either HKCU or HKLM. The suggestion is HKLM.

So, what can you use this for? Well, it turns out this add-in has a lot of uses and as I have started discussing it with other support folks at Microsoft, several use cases came out:

  1. You have a lot of add-ins that you need to have loaded with Outlook. They keep getting disabled by Outlooks resiliency feature, so you add policy settings to prevent them from being disabled, but now Outlook takes forever to launch. You can now set only DLAME to be resiliency policy blocked and then delay load all your other add-ins.
  2. Because it is a .NET/VSTO add-in, added to the above scenario, you can have all your VSTO add-ins load after Outlook has completed loading all other add-ins.
  3. Because the loading occurs on a background thread, the user will see Outlook fully load and then will start to see the other add-ins load (Ribbons and buttons appearing) after they are able to see their inbox and start reading/selecting items.

Bottom line, this add-in is useful for helping an enterprise manage their add-in without impacting the loading of Outlook or user productivity.

However, there is ONE major caveat. You will need to thoroughly test your add-ins because some add-ins might not like being loaded AFTER the fact. Technically, I have not found any that behave this way, but there could be some that register to certain events (like Application_Load and NewExplorer) that will not get fired if loaded after Outlook is already fully loaded.

Using NPM to Publish and Update Packages

This blog post is more for me than you. I come from an era when command line was the only way to get things done. The folks that were able to do that in the 1980’s and early 1990’s, were called…

nerd

Well, for some reason, after advancements in GUI (Graphical User Interfaces) we are back to command-line interfaces. I have heard an argument that this makes it easier to build in voice command interfaces, but I do not see myself saying: “npm install”. I believe it came about because it is easier to create a command line interface quickly for free than it is to create a graphical one. Just sayin’. wlEmoticon-winkingsmile.png

With that said, lets get down the business. I published OfficeJs.dialogs to NPM and found a few last minutes bugs and needed to update it. Well, this seemed easy enough, but I was getting some error about my git working directory:

git working directory dialogs not clean

This turns out to happen because I needed to do both a push and a pull. Not sure why, but I did a push and sync and that did not resolve the issue. I had to do a pull from git too:

menu

Next, I had to then do a version update. To do this you type this in the Terminal window in VS Code once it is pointed to the repository folder:

npm version patch

This will add a single point to the version, so for me that was from 1.0.1 to 1.0.2. Next, you issue a single command:

npm publish

This will publish version 1.0.2 (in my case) to the node module in the sky (npmjs.com). Next, I then went to my project where I am using it and then issue this command:

npm update officejs.dialogs

And just like that, I had the latest version. Seems simple enough, but it took a while for me to research this and get it working. And since these are all command lines without a graphical ability to “hunt and peck” for the right menu item, I am writing it down for posterity. I will likely be referring to this post for myself again in the future.