Office js Dialog api 16.13 Word doesn't open dialog next time - ms-word

I have following code and it's being triggered form a task pane button:
Office.context.ui.displayDialogAsync(
dialogUrl,
{
width: 60,
height: 60,
requireHTTPS: false,
displayInIframe: false
},
asyncResult => {
dialog = asyncResult.value;
if (asyncResult.status === "failed") {
dispatch(MessageActions.showError(asyncResult.error.message));
dialog.close();
} else {
dialog.addEventHandler(Office.EventType.DialogMessageReceived, arg => {
dispatch({ type: LOADED });
dialog.close();
});
dialog.addEventHandler(Office.EventType.DialogEventReceived, arg => {
if (arg && arg.error === 12006) {
dispatch({ type: LOADED });
}
});
}
}
);
Once I called this snippet I get an error
Error code - 12007 .A dialog box is already opened from the task pane.
A task pane add-in can only have one dialog box open at a time.
but really it's not. For previous versions, it worked just fine. Is there anybody who knows what's happened or I might be doing now something wrong?
This is only reproducible on MacOs 10.13.4 and Word v16.13 (18.05.13). Word for
Windows and Word Online work perfectly.

Related

Word-Add in CreateDocoment gives AccessDenied

I've created a simple word plugin and want to create a document based off another document.
I've stripped down the code
function WordLoadDocument(msg) {
Word.run(context => {
var myNewDoc = context.application.createDocument();
myNewDoc.properties.load();
/*
myNewDoc.properties.customProperties.add("fileId", file.id);
myNewDoc.properties.customProperties.add("fileName", file.name);
myNewDoc.properties.customProperties.add("attachId", attach.id);
myNewDoc.properties.customProperties.add("attachName", attach.name);*/
myNewDoc.open();
return context.sync()
}).catch(error => {
if (error instanceof OfficeExtension.Error) {
console.log(
"Error code and message: " + JSON.stringify(error.debugInfo)
);
console.log(error)
}
});
But I just get
Error code and message: {"code":"AccessDenied","message":"AccessDenied","errorLocation":"Application.createDocument","statement":"var createDocument = v.createDocument();"...
It doesn't seem to matter what I do I just always get the error - even before I add in the data..
The manifest has ReadWriteDocument which seems to be the 'max'
https://learn.microsoft.com/en-us/javascript/api/manifest/permissions?view=word-js-1.4
Is there something I'm missing.
I'm on Word desktop and sideloading the app via network - could this be a permissions on the machine / type issue?
So I've worked this one out - basically the issue is that I had the add-in in a dialog box (displayDialogAsync). Word doesn't like it and hence the error.

I am developing VS Code extension and I need to capture the call stack records and log the result

I am writing a simple VS Code extension that suppose to just log the call stack in the console at specific point while debugging a code.
I was able to write a code to retrieve the current session of debugging, the break points and things like this, but I failed to find any property or method to allow me retrieve the call stack records.
This is the code I wrote:
export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "sampleextension1" is now active!');
let disposable = vscode.commands.registerCommand('sampleextension1.hello', () => {
vscode.window.showInformationMessage('Hello World from sampleextension1!');
vscode.commands.executeCommand('editor.action.addCommentLine');
vscode.debug.onDidStartDebugSession(x => {
});
vscode.debug.onDidChangeActiveDebugSession(c => {
var b = vscode.debug.breakpoints[0];
});
});
context.subscriptions.push(disposable);
}
As you see in the code, there is an event handler for onDidChangeActiveDebugSession which enables me to capture the session of the debugging but no chance to find how to capture the stack trace.
I went through the documentation but it's not helpful though.
I was able to achieve what I want by sending a CutomRequest to the debugging session to retrieve the stack frames.
More information could be found in the DAP page here
The code is as shown below:
x.customRequest('stackTrace', { threadId: 1 }).then(reply => {
const frameId = reply.stackFrames[0].id;
}, error => {
vscode.window.showInformationMessage(`error: ${error.message}`);
});
or more efficient is to register tracker as shown below:
vscode.debug.registerDebugAdapterTrackerFactory('*', {
createDebugAdapterTracker(session: vscode.DebugSession) {
return {
onWillReceiveMessage: m => console.log(`> ${JSON.stringify(m, undefined, 2)}`),
onDidSendMessage: m => console.log(`< ${JSON.stringify(m, undefined, 2)}`)
};
}
});
The full example is shown here:
export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "sampleextension1" is now active!');
let disposable = vscode.commands.registerCommand('sampleextension1.hello', () => {
vscode.window.showInformationMessage('Hello World from sampleextension1!');
vscode.commands.executeCommand('editor.action.addCommentLine');
vscode.debug.onDidStartDebugSession(x => {
// x.customRequest("evaluate", {
// "expression": "Math.sqrt(10)"
// }).then(reply => {
// vscode.window.showInformationMessage(`result: ${reply.result}`);
// }, error => {
// vscode.window.showInformationMessage(`error: ${error.message}`);
// });
x.customRequest('stackTrace', { threadId: 1 }).then(reply => {
const frameId = reply.stackFrames[0].id;
}, error => {
vscode.window.showInformationMessage(`error: ${error.message}`);
});
});
vscode.debug.onDidChangeActiveDebugSession(c => {
var b = vscode.debug.breakpoints[0];
});
vscode.debug.registerDebugAdapterTrackerFactory('*', {
createDebugAdapterTracker(session: vscode.DebugSession) {
return {
onWillReceiveMessage: m => console.log(`> ${JSON.stringify(m, undefined, 2)}`),
onDidSendMessage: m => console.log(`< ${JSON.stringify(m, undefined, 2)}`)
};
}
});
});
Steps to run:
F5 to run the Extension Dev Environment.
Ctl+Shift+P then write your cmd, in my case it was Hello
Then F5 to start the debugging in the Dev Environment then you will be able to see the result.
Hope it helps

How to test in SAPUI5 with OPA5 if a dialog is successfully closed? (Negative testing)

I wonder how to test with OPA5 if a Dialog is successfully closed after pressing the corresponding button.
This is how I test if the dialog is open:
{
// ...
iShouldSeeTheSortDialog: function () {
return this.waitFor({
controlType: "sap.m.ViewSettingsDialog",
id: "sortDialog",
fragmentId: "sortFragment",
success: function () {
Opa5.assert.ok(true, "The sort dialog is open");
},
errorMessage: "Did not find the sort dialog control"
});
},
}
Now I'm looking for the exact opposite test case. I would like to search for the sortDialog and throw a success if it is not found anymore.
Could you please suggest a solution?
I found the answer myself, maybe it will be helpful for someone else.
If you want to check if a dialog has been closed but not destroyed, you can do it this way:
{
//..
iShouldNotSeeDialog: function () {
return this.waitFor({
id: "dialogID",
visible: false,
success: function (oDialog) {
Opa5.assert.notOk(oDialog.getVisible(), "Dialog is not visible -- OK");
},
errorMessage: "Checking Field: dialogID -- Assertion Failed"
});
}
}
If you want to check if a dialog has been destroyed, you can do this as follows:
{
//..
iShouldNotSeeDialog: function () {
return this.waitFor({
success: function () {
var bExists = (Opa5.getJQuery()("#" + "dialogID").length > 0);
Opa5.assert.notOk(bExists, "Dialog doesn't exist -- OK");
},
errorMessage: "-- Assertion Failed"
});
}
}

TinyMCE 5.7 failure callback returns "[object Object]" no matter what

Seemingly strange problem here: I've got TinyMCE 5.7 up and running with the images_upload_handler function configured per the docs. If the upload is a success, everything works great. However, if the upload is a failure, then the dialog box that should output the failure message simply outputs "[object Object]".
Screenshot: Failure callback output
I find that this is the case whether I invoke the failure callback in the images_upload_handler function just as the docs dictate...
function gg_image_upload_handler (blobInfo, success, failure, progress) {
[...]
if (xhr.status < 200 || xhr.status >= 300) {
failure('HTTP Error: ' + xhr.status);
return;
}
[...]
}
...or if I make the entire images_upload_handler function a failure callback with a simple string, taking all the other variables (including the PHP upload handler) out of it:
function gg_image_upload_handler (blobInfo, success, failure, progress) {
failure('hello!');
return;
}
Notably, if I change the second example from "failure('hello!');" to "success('hello!');" then there is no problem: When I upload a photo in that case, "hello!" appears in the dialog box where the path to the uploaded image would normally appear.
I can't find anyone else who's had an issue with the failure callback, so I fear I've done something silly, but it seems weird that everything else works and this part does not. Any thoughts? Full Javascript code follows:
function gg_image_upload_handler (blobInfo, success, failure, progress) {
var xhr, formData;
xhr = new XMLHttpRequest();
xhr.withCredentials = false;
xhr.open('POST', 'handlers/tinymce_photo_handler.php');
xhr.upload.onprogress = function (e) {
progress(e.loaded / e.total * 100);
};
xhr.onload = function() {
var json;
if (xhr.status === 403) {
failure('HTTP Error: ' + xhr.status, { remove: true });
return;
}
if (xhr.status < 200 || xhr.status >= 300) {
failure('HTTP Error: ' + xhr.status);
return;
}
json = JSON.parse(xhr.responseText);
if (!json || typeof json.location != 'string') {
failure('Invalid JSON: ' + xhr.responseText);
return;
}
success(json.location);
};
xhr.onerror = function () {
failure('Image upload failed due to a XHR Transport error. Code: ' + xhr.status);
};
formData = new FormData();
formData.append('file', blobInfo.blob(), blobInfo.filename());
xhr.send(formData);
};
tinymce.init({
selector: "textarea#editor",
images_upload_handler: gg_image_upload_handler,
images_reuse_filename: true,
skin: "oxide",
plugins: "lists, link, image, media, image code",
relative_urls: false,
remove_script_host: false,
toolbar:
"h1 h2 h3 h4 h5 h6 bold italic strikethrough blockquote bullist numlist backcolor | link image media | removeformat help",
image_caption: true,
image_advtab: true,
image_class_list: [
{title: 'Responsive', value: 'img-fluid'}
],
content_style: 'img { max-width: 75%; height: auto; }',
menubar: false,
setup: (editor) => {
// Apply the focus effect
editor.on("init", () => {
editor.getContainer().style.transition =
"border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out";
});
editor.on("focus", () => {
(editor.getContainer().style.boxShadow =
"0 0 0 .2rem rgba(0, 123, 255, .25)"),
(editor.getContainer().style.borderColor = "#80bdff");
});
editor.on("blur", () => {
(editor.getContainer().style.boxShadow = ""),
(editor.getContainer().style.borderColor = "");
});
}
});
Unfortunately, this is a bug introduced in TinyMCE 5.7.0 as reported here: https://github.com/tinymce/tinymce/issues/6579. This will be fixed in the upcoming TinyMCE 5.7.1 patch release, however for now the best workaround is to downgrade to TinyMCE 5.6.2 sorry.

Escaping from a nested material-ui dialog

When I have one dialog open and it opens another and I hit escape it closes both.
Is there any way to make the escape only close the top most dialog?
I dont think this will be possible without some hassle. In the dialog render function, this eventlistener is rendered and there is no prop that allows you to overwrite this.
{open &&
<EventListener
target="window"
onKeyUp={this.handleKeyUp}
onResize={this.handleResize}
/>
}
Which calls this method.
handleKeyUp = (event) => {
if (keycode(event) === 'esc') {
this.requestClose(false);
}
};
source
You can however dive into in node_modules/material-ui/Dialog/dialog.js and delete that code or change it. Removing this line will prevent it from ever closing on esc, but will count for all dialogs. Maybe after that you can implement a keycode event listener in you own class that handles the closing of the modal.
if ((0, _keycode2.default)(event) === 'esc') {
_this2.requestClose(false);
}
EDIT: possible solution.
I created 2 components, a DialogContainer class component and a Dialog functional component. To use this you have to npm install --save react-event-listener.
For this to work you still have to remove the above code from the node_modules.
When only one dialog is opened it will close that dialog when esc is clicked. If two dialogs are opened it will first close dialog2 and leave dialog1 open.
DialogContainer.js
import React, { Component } from 'react';
import Dialog from './Dialog';
import RaisedButton from 'material-ui/RaisedButton';
import EventListener from 'react-event-listener';
export default class DialogContainer extends Component {
state = {
openDialog1: false,
openDialog2: false
};
handleDialog1Open = () => {
this.setState({ openDialog1: true });
};
handleDialog2Open = () => {
this.setState({ openDialog2: true });
};
handleDialog1Close = () => {
this.setState({ openDialog1: false });
};
handleDialog2Close = () => {
this.setState({ openDialog2: false });
};
handleKeyUp = (event) => {
// 27 = esc
if (event.keyCode === 27) {
if (this.state.openDialog1 && this.state.openDialog2) {
this.handleDialog2Close();
} else {
this.handleDialog1Close();
this.handleDialog2Close();
}
}
};
render() {
return (
<div>
{(this.state.openDialog1 || this.state.openDialog2) &&
<EventListener
target="window"
onKeyUp={this.handleKeyUp}
/>}
<RaisedButton label="Open1" onTouchTap={this.handleDialog1Open}/>
<RaisedButton label="Open2" onTouchTap={this.handleDialog2Open}/>
<Dialog
openOtherDialog={this.handleDialog2Open}
open={this.state.openDialog1}
handleClose={this.handleDialog1Close}
number={1}/>
<Dialog
open={this.state.openDialog2}
handleClose={this.handleDialog2Close}
number={2}/>
</div>
)
}
};
Dialog.js
import React from 'react';
import Dialog from 'material-ui/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
const DialogCustom = ({ open, handleClose, number, openOtherDialog}) => {
return (
<div>
<Dialog
title="Dialog"
modal={false}
open={open}
onRequestClose={handleClose}
>
{`this is dialog ${number}`}
{openOtherDialog &&
<RaisedButton label="Open2" onTouchTap={openOtherDialog}/>
}
</Dialog>
</div>
);
};
export default DialogCustom;
There is nearly always a better solution than having two dialogs/modals open at the same time. In our material-design app using MUI, we have this situation on a few occasions. The way we handle it: close the "underneath" dialog when the "top" dialog opens. Then (if needed), you can re-open the "underneath" dialog when closing the "top" dialog. Seems like a lot of work, but stacking dialogs gets to be tricky with both the code and the UX considerations.