If you have been developing OfficeJS add-ins for Outlook Online (or Exchange 2016 Outlook Web Access) you might not know that you now have the ability to create OnSend add-ins. That is add-ins that can trap the send of an email, test for conditions (such as getBodyAsync() or getSubjectAsync() to look for content) and if they fail, prevent the message from being sent. I recently blogged about it here:
First thing to note about these add-ins is that they cannot be created for or uploaded into the store. The second thing to note is that they MUST be configured first in order to run. The third thing to note is that if you are building an on-prem Exchange based solution, you have to have Exchange 2016 CU6 installed and a bit more. The full details of how to configure the environments (either Office Online or On-prem) are detailed here:
So, I kind of skipped v1.0.6, which I promised in this post yesterday. There were some unchecked changes on a different laptop that I forgot in v1.0.6, so I published v1.0.7 this morning with all the updates. Some notable update:
Fixed dialog flashing by hiding the body until the form is ready to be shown. Before you might get a flash of all the controls on the form as they were not hidden before.
Internal clean-up and message handling. In the message pump between the dialogs.html and dialogs.js, I cleaned up the pump to use internally standardized messages.
Fixed some JSDoc information that was wrong. And there is likely still more.
Fixed some things that were not working correctly with the progress dialog.
Small tweeks and comments, code clean-up
The latest version is now on GitHub. I have also completed all the documentation and updated it to the latest usage information, code examples and screenshots.
I also published the latest version to NPM. Simply type this in you code terminal window:
npm -install officejs.dialogs
CDN Update
I still have a published CDN for OfficeJS.dialogs, but at this point I am going to suggest against using it. I have encountered a number of issues with my message pump when loaded cross-domain. Specifically:
you will be able to show a MessageBox, but the Update() method will not work
you will be able to show a Progress dialog, but the Update() method will not change the dialog. The progress bar will never advance.
What is happening is that I was going to need for **you** the developer to provide me your own proxyHTML file (pointing to my CDN/proxy.js library) that I will do the following:
Add an iframe, load my html file in that iFrame, post the dialog settings to the iFrame where my dialog in the iFrame gets it, and writes it to localStorage on the CDN domain.
Window.replace the contents with my dialogs.html from the CDN. And since the localStorage now has the dialog settings, configure the dialog.
So far at this point everything worked. From HERE is where I am pushing my CORS and JavaScript to the edge of sanity…
I then create an hidden iFrame in my dialog and then load your proxy html file. I attach to the body change event inside the iFrame.
I then start a message pump in the proxy looking for changes to localStorage.
If a new message comes from your code with an Update() on MessageBox or Progress, I then get it from the localStorage in a message and write it to the body, therefore updating the iFrame in my dialog, thereby triggering the change event I latched on to, allowing me to write that value to the CDN localStorage where the message pump in dialog will get the message and update the form.
That hurt my brain writing that out. And maybe that is more for my posterity since it took me Binging the Internet to death (I don’t use to the G word folks ), just to get that far. My pretzel, I mean head hurts.
Bottom line, I want to get OfficeJS.dialogs to work cross-domain. I am not sure if the above method is the right approach. I have asked far brighter minds than my own and watched Autie Anne’s Syndrome set in almost immediately. So, if any of you have some ideas on how I can establish 2-way communication between domains like this (without using some crazy huge library), please let me know.
I have been spending a lot of time in the Officeui.dialog lately. One of my customers has been too and it has been an adventure working out exactly the best way to get messages displayed while running code in the background asynchronously.
I am not sure if this problem is limited to the online version of Outlook, but this is where I have been seeing the problem (and where I have spent virtually all of my time). If my code tried to open two dialogs (using Office.context.ui.displayDialogAsync()) one right after the other, the second dialog would not ever be displayed. If I waited a period and then tried again, it would. But we don’t want that. We want boom-boom, dialogs. When I looked at the console, I would see an error like the following:
Uncaught TypeError: Cannot read property ‘addEventHandler’ of undefined
Or, if I read the error object from the displayDialogAsync() function/asyncResult, I would see this:
{name: “Display Dialog Error”, message: “The operation failed because this add-in already has an active dialog.“, code: 12007}
Here is an example of some code that will reproduce the issue:
[code lang=”javascript” collapse=”true” title=”click to expand if the github.com embedding below is not visible.”]
var i = 0;
function displayDialog() {
var url = "https://localhost:3000/test.html";
Office.context.ui.displayDialogAsync(url,{height:20, width:30, displayInIframe:true},
function (asyncResult) {
var dialog = asyncResult.value; // get the dialog
var error = asyncResult.error;
if(dialog == undefined && error.code > 0) {
// log the error
console.log(error.message);
} else {
// attache the events
dialog.addEventHandler(Office.EventType.DialogEventReceived, function (arg) {
// close this dialog, open the next
dialog.close();
i++;
if(i<4) {
displayDialog();
}
});
dialog.addEventHandler(Office.EventType.DialogMessageReceived, function (arg) {
// close this dialog, open the next
dialog.close();
i++;
if(i<4) {
displayDialog();
}
});
}
});
}
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Notice I had used dialog.close(), but it did not work as designed. What I believe is happening is that the previous dialog is still in memory and has not been cleaned up. What needs to likely happen is a closeAsync().
In order to resolve this, I created the following function: dialogCloseAsync(). This works by issuing the close() and then attempting to add an event handler to the dialog in ansyc (setTimeout) loop. When it errors, we trap the error and issue the async callback. It is a bit ugly as we are trapping an error to get around the problem, but this was the only way I could find a way around the problem. Here is what the function looks like:
[code lang=”javascript” collapse=”true” title=”click to expand if the github.com embedding below is not visible.”]
/**
* Closes the currently open dialog asynchronously.
* This has an ugly workaround which is to try to set a new
* event handler on the dialog until it fails. When it failed
* we know the original dialog object was destroyed and we
* can then proceed. The issue we are working around is that
* if you call two dialogs back to back, the second one will
* likely not open at all.
* @param {Office.context.ui.dialog} dialog The dialog to be closed
* @param {function()} asyncResult The callback when close is complete
*/
function dialogCloseAsync(dialog, asyncResult){
// issue the close
dialog.close();
// and then try to add a handler
// when that fails it is closed
setTimeout(function() {
try{
dialog.addEventHandler(Office.EventType.DialogMessageReceived, function() {});
dialogCloseAsync(dialog, asyncResult);
} catch(e) {
asyncResult(); // done – closed
}
}, 0);
}
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
I had been encountering this issue with different systems when developing the OfficeJS.dialogs library and had tried to set a timeout before I showed each dialog. That worked on some systems, but on others the timeout needed to be longer. So, setting a default timeout did not work. Using this in the original sample, provided above, the code would look like this:
[code lang=”javascript” collapse=”true” title=”click to expand if the github.com embedding below is not visible.”]
var i = 0;
function displayDialog() {
var url = "https://localhost:3000/test.html";
Office.context.ui.displayDialogAsync(url,{height:20, width:30, displayInIframe:true},
function (asyncResult) {
var dialog = asyncResult.value; // get the dialog
var error = asyncResult.error;
if(dialog == undefined && error.code > 0) {
// log the error
console.log(error.message);
} else {
// attache the events
dialog.addEventHandler(Office.EventType.DialogEventReceived, function (arg) {
// close this dialog, open the next
dialogCloseAsync(dialog, function() {
i++;
if(i<4) {
displayDialog();
}
});
});
dialog.addEventHandler(Office.EventType.DialogMessageReceived, function (arg) {
// close this dialog, open the next
dialogCloseAsync(dialog, function() {
i++;
if(i<4) {
displayDialog();
}
});
});
}
});
}
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
As I found this workaround, I have updated OfficeJS.dialogs to use dialogCloseAsync(). Now, the MessageBox, Wait and Form objects will use closeDialogAsync() commands to replace the original closeDialog() commands I provided previously. I will be blogging about the updates to v1.0.6, shortly.
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:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
/**
* 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);
}
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
// 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
}
};
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
Wait.Show(null, true, function() {
Alert.Show("The user cancelled.");
});
setTimeout(function(){
Wait.CloseDialog();
Alert.Show("Done!");
}, 15000);
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
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
Per my previous blog entry on Docs.com being retired, I have finally found the time to go through my blog and update all my original Docs.com samples to now point to GIST. This was a lot of work, but it had to be done. If you find an entry in my blog still pointing to Docs.com, please let me know.
Several customers have asked me if OfficeJS has something similar to a Visual Basic or C# MessageBox.Show() function. The answer is no. And for a long time there was not even a dialog option. With the latest releases of the OfficeJS libraries comes a new dialog feature. Yet to get a standard MessageBox, you will still need to create it from scratch. Or, at least until this blog post you did. I have created a helper library the consists of two files:
dialogs.js
dialogs.html
To reference this library you can do any of the following:
NOTE: This assumes your page is in the root of your project. The key point is that it is added to your node_modules when you use NPM and this is how you will reference it.
Once referenced you can then call a MessageBox like this:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
MessageBox.Reset();
MessageBox.Show("This is a test with a lot of text that simply has not point but to show you what " +
"happens when you place a lot of text in a MessageBox for any point other than to " +
"place a whole lot of text in the MessageBox.",
"This is the Caption",
MessageBoxButtons.AbortRetryCancel,
MessageBoxIcons.Stop,
true, "Check this if you want me to stop nagging you.",
function(buttonPressed, checked) {
console.log("The button pressed was: " + buttonPressed);
console.log("The checkbox was checked? " + checked);
});
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
InputBox.Reset();
InputBox.Show("What value do you want to enter?",
"InputBox caption",
"Default value", function(result) {
var msg = "";
if(result.length == 0) {
msg = "The user pressed cancel.";
} else {
msg = "The user entered: " + result;
}
console.log(msg);
});
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
You can show a custom form of your own design like this:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
Form.Reset();
Form.Show("/test.html",10,20,false,function(result){
var yourJSON = JSON.parse(result).Result;
// if you placed false in the 4th param you must
// handle the close of the form
Form.DialogClose();
});
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Here is an example of what the above code looks like:
It is important to note that like everything else in the OfficeJS world this is an async dialog. This also means it is non-blocking. This means any code you do not have in your callback method will continue to run. And if you are wanting to display multiple message boxes at the same time – you cannot. The last one you try to display wins, the others will be gone. Most everything in this dialog is just like you will remember from the good ol’ Visual Basic/C# MessageBox and InputBox. Even the constants for MessageBoxButtons and MessageBoxIcons are the same. But, I added a little flare and it probably helps with the best practices in OfficeJS to not nag the user with dialogs, and that is the ability to add a check box to the form so you can ask the user if they do not want to be bothered by your code anymore.
For the MessageBox, the withcheckbox and checkboxtext are there to give you that ability. Additionally, you see the callback method (asyncResult) that will return once the use dismissed the dialog. It will return with two pieces of information:
The button the user clicked in string format. So “Yes” or “Cancel” will be what you see here.
A Boolean representing whether the check box was checked or not.
For the InputBox, the callback method (asyncResult), will return one piece of information. If will return the text the user entered, or it will return nothing (an empty string), if the user pressed cancel.
The Form method will return a JSON object:
Error: { }, // Error object
Result: { }, // JSON from form
Cancelled: false // boolean if formed cancelled with X
The Result object will be the JSON from your own form. In your code you will need to call back to the parent like this:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
Office.initialize = function(reason) {
$(document).ready(function () {
$("#okButton").click(function() {
// notify the parent
Office.context.ui.messageParent("My custom message.");
});
});
};
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
You will also see in the examples above, I call .Reset() before I issue a new dialog request. This is because the objects are global and this is a way to be certain to clean up anything in memory that might be associated with a previous dialog. In my testing, I never really had problems like this, but I added it as an extra precaution.
Also, note, I have only tested this in Outlook OWA, I have not had a chance to test it in Excel, Word, PowerPoint or even in the full Outlook client. So, if you encounter issues in those other clients, please let me know.
Finally, I want to call out the OfficeJS Helpers. This library provides a lot of help with authorization dialogs, but also has a simple method for displaying messages using OfficeHelpers.ui.notify(). You can install it into your project using NPM:
As I delve ever deeper into the world of Node, I have found the ability to install packages with NPM quite handy. I do this from VS Code using the Terminal window. I just type:
npm install <packagename>
As I have been developing different packages for my customers, I have found the need to install code that I have been reusing over and over again. Most importantly, easyEws. So, I created a npmjs account (davecra) and I published easyEws. But what is even better and what I was after, is I can now install the latest version of easyEws by going into the Terminal window in VS Code and typing this:
I am “newish” to web development in the modern era. By modern era I mean, that I was writing webpages before “getting on the web” was cool. Before the movie “You Got Mail” came out, when AOL, dialup and Netscape were all still “the thing.” So, I know web development back then, probably up through 2007’ish. And I have done very little serious web development until 2 years ago when I really started delving into OfficeJS. So here are some things I have learned and would like to admit I did not know… I mean, pass along to you:
Node. This heralds back to my previous post on Yo Office. In this post, I call out that NodeJS/BrowserSync is a powerful feature. I can safely say, as I have been working with it more and more, it has changed my life for the better. I have also been using Node and VS Code in an effort to understand this newer way of development. I have had a number of colleagues convince me to keep on keeping on with it – it will grow on me, they swear. Ok… So, what I like is when I hit save in VS Code and go back to the browser and click my add-in button (for a function-file), or open my taskpane again – it is current. I DO NOT have to refresh the browser. Browser-Sync takes care of all this for me.
Chrome. If you are debugging outside of Visual Studio, I have found Chrome to be the best browser with which to debug. Here is why:
It’s Incognito mode is the best option for making sure you always have the most recent files and things are not cached. Edge and IE have private modes, but there is the next issue…
Edge and IE are tied into Windows and when you try to log into your developer tenant from them, it automatically grabs your credentials from Windows and takes you to your company email. Ugh!
Incognito still lets you (with warnings) load certain extensions and you also get form fill, so it makes getting into your tenant mailbox super quick and easy.
F12, developer tools. Edge and IE also have, but look at Chrome’s: Enough said there.
console.log(). This is a bit of a no brainer, but I have found that sprinkling my code with this helps me get a good idea of my code flow, especially with Async() hell that you can get into with OfficeJS.
debugger; – this has saved my life. I know, I am a “noob,” but I had no idea how to set a breakpoint in my code and get the browser to stop there, right there… no not there, RIGHT THERE!!! There is a window in my office with easy access to the pavement 4 stories below. One day, the day when I found this (after much frustration with my inability to write coherent JavaScript – a common problem I have), I was about to see if I could bounce. So, what you do is place this one word in your code, and if you have the developer tools open… viola! OMG:
debugger;
try/catch – In C#, especially with the debugger attached, I sometimes worried about error handling after the fact. Partially because I was not sure all the exception types I would want to catch or just use a general exception handler. But to say unexpected things happen in JavaScript and OfficeJS all the time is an understatement. Especially if you pretend to be a JavaScript developer like me.
I use the console to always output errors.
And, I know this is coming, TypeScript makes things so much easier in this area. As a matter of fact, I know one colleague that will be telling me “of course you do not bounce,” and my problems would be so much less had I used TypeScript in the first place. For the record, TypeScript makes a horribly disastrous JavaScript developer like me into an only moderately bad one. But, unfortunately, all my clients are writing code in JavaScript, so here I must suffer.
I have been working on a number of projects for my customers and recently, dialogs have taken front and center stage. The Office.context.ui Dialogs are powerful, albeit a tad confusing and the documentation suffers from a few easily missed points. Here is the documentation:
But in this post, I hope to explain everything I have learned. To start off with here is the code to issue the dialog:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
Office.context.ui.displayDialogAsync(‘https://localhost:3000/function-file/dialog.html’,
{ height: 20, width: 30, displayInIframe: true },
function (asyncResult) {
dialog = asyncResult.value;
// callbacks from the parent
dialog.addEventHandler(Office.EventType.DialogEventReceived, processMessage);
dialog.addEventHandler(Office.EventType.DialogMessageReceived, processMessage);
});
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The first one is an event receiver and really this is the event handler for errors, such as being unable to open the dialog or, most importantly, the user closed the dialog by clicking the (X) in the upper right of the dialog. There are a series errors you can catch, but specifically, the dialog cancel is this:
12006
The dialog box was closed, usually because the user chooses the X button.
The second one is a handler for messages coming from the dialog. These messages can be anything, but is usually a string or a JSON string. You can send a message from the dialog like this:
When the dialog issues a message using the code above, the function defined in the event handler is called. For example, if the user clicks an OK button or Submit button, you can pass the stringified values from the form back to the callback function. From there the dialog actually remains open until the caller issues a close, like this:
[code lang=”javascript”]
// close the dialog
dialog.close();
[/code]
In the example above where I make the displayDialogAsync call, you will see I defined the SAME callback function for both dialog events. I did this because the results can be parsed by the same function. Here is what my function look like:
[code lang=”javascript” collapse=”true” title=”click to expand if the embedding below is not visible.”]
function processMessage(arg) {
// close the dialog
dialog.close();
// procress the result
if(arg.error == 12006) {
// user clicked the (X) on the dialog
sendEvent.completed({ allowEvent: false });
} else {
if(arg.message=="Yes") {
// user clicked yes
sendEvent.completed({ allowEvent: true });
} else {
// user clicked no
sendEvent.completed({ allowEvent: false });
}
}
}
[/code]
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
What this sample add-in does is pops up a dialog box anytime you press Send on an email with a question: “Are you sure?” If you click Yes, it sends, if you click “no” is blocks the send. Here is what that dialog looks like:
If you have followed the steps from my Yo Office post, you will be able to open the project in VS Code, and from the terminal, launch it with:
npm start
Next, you will need to follow the steps to enable the OnSend policy in your account and then you will need to install/sideload the manifest. From there you will not see any appearance of the add-in at all, until you press the Send button.
NOTE: At the point I first tested it on June, 13th, 2017, there is a KNOWN ISSUE with the certificates created fro a “yo office” build. If you have not resolved the certificates issue you will be able to start the project in Node.js, but the add-in will fail to run. You need to perform the steps outlined here to correct it: