Office.js displayDialogAsync error when displayInIframe: false - outlook

I'm trying to display, in an outlook web add-in, a dialog from a taskpane using the displayDialogAsync function. At first, I used displayInIframe: true and everything was working wonderfully, but for some reason I needed it to display in its own page.
So I changed the options to displayInIframe: false, and that causes a prompt to open. When it opens and I click Allow, I get a JSON.parser error.
Uncaught SyntaxError: Unexpected token d in JSON at position 0 at JSON.parse (<anonymous>) at O (outlook-web-16.01.js:20:204476) at HTMLInputElement.Y.f.onclick (outlook-web-16.01.js:20:196995)
It's comming from this line: var windowName = JSON.parse(window.name);
I tried turning the prompt off using promptBeforeOpen: false, but as it says in the docs, "When this option is set to false, Office on the web will not prompt the user to allow the add-in open a dialog, and the Office dialog will not open."
I was wondering if I was missing something, or if you can't actually open a dialog outside of an iframe in a taskpane?
Here is my code:
const dialogUrl = "https://office365.localhost.com/test.html";
Office.context.ui.displayDialogAsync(
dialogUrl,
{
displayInIframe: false,
height: 80,
width: 80
},
(result) => {
//Code
}
});

Related

How to Make FireFox recieve background push notification without loading page?

I am using FCM for web push notifications.
All worked fine until suddenly Firefox stopped delivering push notifications except the page is open in the browser.
If the page is loaded and not in focus, notifications come in. I console.log()'d the onBackgroundMessage payload and I can confirm that the service worker receives it. But if I close that tab and send a push notification, it does not receive it.
The same setup works on Chrome, Opera, and Edge just fine no errors. Is there something with firefox?
Firefox version: 88.0.1 (64-bit)
in my Service Worker I have:
messaging.onBackgroundMessage(function (payload) {
// Customize notification here
var action_label;
if('action_label' in payload.data){
action_label = payload.data.action_label;
} else{
action_label = "Details";
}
const notificationTitle = payload.data.title;
const notificationOptions = {
body: payload.data.body,
icon: payload.data.icon,
requireInteraction: true,
data: {
click_action: payload.data.click_action,
url:payload.data.click_action
},
actions: [
{
action: "open_url", title: action_label
}
]
};
self.registration.showNotification(notificationTitle, notificationOptions);
});
This had to do with Firefox quitting instead closing, obtainable in MacBooks.
Not a real technical issue.

How do i moniter CONTROL KEY press event on firefox using only javascript?

i have code that can monitor control key press event on chrome but its not working on firefox
this works fine on chrome
onkeypress = (e) =>{
console.log(e);
if(e.ctrlKey && e.code == "KeyZ"){
document.write("do somthing")
} }
this is what iam getting on chrome
KeyboardEvent {isTrusted: true, key: "", code: "KeyZ", location: 0, ctrlKey: true, …}

Single sign on in Teams application between tabs and the bot

Using the Bot Framework w/ Microsoft.Bot.Builder v4.6.3
Is it possible to have users sign in only once using the web-based authentication flow, doesn't matter if they sign in via tabs or via bot conversation? If they sign in via a link from a tab, I'd like to have the bot know about this.
I have tried the following for test, omitting any security checks:
All pages are with the following js files imported:
https://statics.teams.microsoft.com/sdk/v1.4.2/js/MicrosoftTeams.min.js
https://cdnjs.cloudflare.com/ajax/libs/oidc-client/1.9.1/oidc-client.min.js
On load, the tab page executes microsoftTeams.initialize();
Add a button to the tab page:
<button onclick="authenticate()">Authenticate</button>
The authenticate function contains the following:
function authenticate() {
microsoftTeams.authentication.authenticate({
url: window.location.origin + "/tabs/tabAuthStart",
width: 600,
height: 535,
successCallback: function (result) {
// The debug function just displays what's sent to it using document.write()
debug(result);
},
failureCallback: function (reason) {
debug(reason);
}
});
}
The tabAuthStart page contains the following script which is executed on page load:
microsoftTeams.initialize();
const mgr = new Oidc.UserManager({
userStore: new Oidc.WebStorageStateStore(),
authority: '<my-identity-server>',
client_id: '<my-id-srv-client>',
redirect_uri: window.location.origin + '/tabs/tabAuthCallback',
response_type: 'id_token token',
scope: '<my-requested-scopes>',
accessTokenExpiringNotificationTime: 10,
automaticSilentRenew: true,
filterProtocolClaims: true,
loadUserInfo: true
});
mgr.signinRedirect();
After a successful sign in at the identity provider, I'm redirected back to /tabs/tabAuthCallback
On load, the /tabs/tabAuthCallback executes the following code:
microsoftTeams.initialize();
var mgr = new Oidc.UserManager({ userStore: new Oidc.WebStorageStateStore(), loadUserInfo: true, filterProtocolClaims: true });
mgr.signinRedirectCallback().then(function (user) {
// I expected something involving a bot to happen after calling this
microsoftTeams.authentication.notifySuccess({
idToken: user.id_token,
accessToken: user.access_token,
tokenType: user.token_type,
expiresIn: user.expires_at
})
}).catch(function (err) {
microsoftTeams.authentication.notifyFailure("UnexpectedFailure: " + err);
});
The pop-up window is closed and the successCallback function from the tab is executed successfully with the user information that I have sent. However, the bot is not in any way notified about this (as far as I know). I have set a breakpoint in the bot controller action resolved by POST /api/messages but it's never hit.
Do I need to handle this manually? I.e. pass the user info to the back-end? But even if so, how do I know which Teams user to associate this user info (i.e. access token) to?
If this is possible to do in a reliable and secure way, would it also be possible in the opposite direction, i.e. having the user token available to the tab if they have already been authenticated from a bot conversation or a messaging extension? Is there a reliable way to identify a Teams user who's navigating tabs, in order to obtain their access token from the back-end, assuming the back-end already obtained them via the authentication mechanism?

Is it possible to record a window without user intervention in recordrtc?

I know it may sound shady, but I'm developing a window recording program (right now using ffmpeg + gdigrab to grab windows) that records
The question is, can I pass the window to be recorded without the user having to choose it?
Thanks!
If you're using Chrome browser, you can open Google Chrome Properties dialog, find the "Target" box and put --enable-usermedia-screen-capturing at the end. E.g.
"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --enable-usermedia-screen-capturing
Now relaunch the Chrome browser.
Screenshot for chrome properties box:
Now try following code on any HTTPs page (or on localhost page):
var screen_constraints = {
mandatory: {
chromeMediaSource: 'screen'
},
optional: []
};
var hints = {
audio: false,
video: screen_constraints
};
navigator.webkitGetUserMedia(hints, function(screen) {
// this is your screen; record it using MediaRecorder or RecordRTC
}, function(error) {
console.error(error);
});
Want to try on HTTP pages? Following flag may work:
--allow-http-screen-capture
Chrome flags reference: http://peter.sh/experiments/chromium-command-line-switches/

Extjs 4 (with a code for 3.4 below) downloading a file returned from a post request

I have seen questions slightly related to this, but none that answer my problem. I have set up an Ext.Ajax.request as follows:
var paramsStringVar = 'param1=1&param2=two&param3=something&param4=etc';
Ext.Ajax.request({
url: '/cgi-bin/url.pl',
method:'POST',
params:paramsStringVar,
timeout:120000,
success: function(response, opts){
var objhtml = response.responseText; //content returned from server side
console.log(objhtml);
}
});
This request retrieves the appropriate content from the backend. One parameter is outputType, which can take values {html, excel, csv}. When returning html to display I am able to handle and display it correctly. Now on to the problem...
When I set the outputType parameter to csv or excel, I get back the appropriate content as csv or tsv(excel) as requested. BUT, I don't want the content, I want a prompt to download the file(csv or excel). How can I have the browser auto prompt the user to download the file instead of just retrieving the text content within extjs?
Version 4.07 so I can't use any 4.1 only features
There seems to be no bulletproof solution but there are several approaches I would try:
1) Use an iframe instead of real XHR to POST data to the server, e.g. <form action="/something" target="myiframe"> where myiframe is the name of your hidden iframe. That way your form would use the iframe (not your main window) to submit data to the configured URL. Your server should set response header as application/octet-stream (or some ither MIME type for binary data) so the browser triggers download. Otherwise (if html returned in your case) you can just retrieve iframe's body innerHTML and display it to the user in UI. While using an iframe (or a new window) instead of XHR doesn't sound like the best idea, this solution seems to be the most reliable so far (and with best browser support).
Here is a slightly modified example from Ext.form.Basic docs page:
Ext.create('Ext.form.Panel', {
title: 'Basic Form',
renderTo: Ext.getBody(),
width: 350,
// Any configuration items here will be automatically passed along to
// the Ext.form.Basic instance when it gets created.
// *THIS* makes the form use a standard submit mechanism, not XHR
/**/standardSubmit: true,
// URL to submit to
url: 'save-form.php',
items: [{
fieldLabel: 'Field',
xtype: 'textfield',
name: 'theField'
}],
buttons: [{
text: 'Submit',
handler: function() {
// The getForm() method returns the Ext.form.Basic instance:
var form = this.up('form').getForm();
if (form.isValid()) {
// Submit the Ajax request and handle the response
form.submit({
success: function(form, action) {
Ext.Msg.alert('Success', action.result.msg);
},
failure: function(form, action) {
Ext.Msg.alert('Failed', action.result.msg);
},
// You can put the name of your iframe here instead of _blank
// this parameter makes its way to Ext.form.Basic.doAction()
// and further leads to creation of StandardSubmit action instance
/**/ target: '_blank'
});
}
}
}]
});
There are two key parameters here (lines marked with /**/):
standardSubmit: true config that you pass to your form will make it do a standard submit instead of XHR.
Passing a target parameter to the form's submit action. This feature is not documented but you can see it being used in Ext.form.action.Submit source code (all options that you pass to Ext.form.Basic.submit() method end up as parameters of Ext.form.action.* instance.
In the example code I put target: '_blank' to demonstrate that it works right away (will create a new browser window). You can replace it with the name of your iframe later but I suggest that you first test how your form submits data to a regular new window and then develop logic that creates and processes an iframe. You will have to process the result inside iframe yourself, thought. It's not that difficult, see Ext.data.Connection.upload() implementation as an example of iframe processing.
ExtJS actually already uses the iframe technique for file uploads. See Ext.data.Connection and Ext.form.field.Field.isFileUpload() for an idea of how it can work.
2) Suggested here: Using HTML5/Javascript to generate and save a file.
If you don't want to go the iframe way, you can try generate data URI from response data and navigate to that URI triggering download:
content = "Hello world!";
uriContent = "data:application/octet-stream," + encodeURIComponent(content);
window.location.href = uriContent;
Again, mimetype is essential here. This worked for me, you should note, however, that browsers impose a size limit to data URIs (256Kb is a safe bet).
3) Another answer in the mentioned thread links to FileSaver.js library the implements the (abandoned?) w3 spec. Usage and demo here. It uses [BlobBuilder] to generate a blob of binary data that is further used to initialize downloads using one of several methods. While this solution seems to work, it uses deprecated APIs and may not be future-proof.
Below is my solution. This is how I have it currently working. The response generates a download/open prompt, based on a response type of text/csv. Note that no iFrame or reference to an iframe are needed. I spent a lot of time hung up on the need for an iFrame, which actually broke my solution. An iFrame is not needed to generate a download prompt. What is needed is a request(submittal) similar to this one, along with a backend generating the appropriate csv with text/csv response header.
var hiddenForm = Ext.create('Ext.form.Panel', {
title:'hiddenForm',
standardSubmit: true,
url: /cgi-bin/url.pl
timeout: 120000,
height:0,
width: 0,
hidden:true,
items:[
{xtype:'hiddenField', name:'field1', value:'field1Value'},
// additional fields
]
})
hiddenForm.getForm().submit()
The standardSubmit line is vital
You don't need to create a form panel and make it hidden in your extjs file. We can add a html form and on click of button in extjs file we can submit the form using the url. This will work both in IE as well as chrome browsers. Below is my code i tried and its working fine,
<form action="<%=fullURL%>/DownloadServlet.do" method="get" id="downloadForm" name="downloadForm" target="_self">
</form>
click:
{
fn: function()
{
document.getElementById('downloadForm').submit();
}
}
To get it working on ExtJS 3.4:
var hiddenForm = new Ext.FormPanel({
id:'hiddenForm',
region: 'south',
method: 'POST',
url: "/cgi/test.wsgi",
height: 0,
standardSubmit: true,
hidden:true,
items:[
{xtype:'hidden', name:'p', value:p},
{xtype:'hidden', name:'g', value:g},
// ...
],
});
linkThis = new Ext.Button({
text: 'Download this CSV',
handler: function() {
hiddenForm.getForm().submit();
},
maxHeight: 30,
});
Remember that in order to make it working, you should put the hiddenForm in any container (i.e. in the same Ext.Window of the button), for example:
risultatiWindow = new Ext.Window({
title: 'CSV Export',
height: 400,
width: 500,
....
items: [...., hiddenForm]
});

Resources