I have developed an add-on using the Firefox Add-on SDK 1.14.
This add-on listens to tabs.ready events to perform an action.
Starting on Firefox 24, the tabs.ready event is no longer fired when a page is loaded by means of a window.open call.
Sample add-on code:
var tabs = require("sdk/tabs");
tabs.on('ready', function(tab){console.log(tab.url)});
Sample page code:
window.open(
'http://stackoverflow.com',
'',
'width=800,height=600,scrollbars=yes,resizable=no,status=yes,location=yes'
);
Am I missing something or the Add-on SDK is not behaving correctly?
Related
I have an add-in that opens a dialog box using Office.context.ui.displayDialogAsync() with displayInIframe: true
I compose an email and open the add-in. Using the add-in I select the files I wish to attach to the email. On the desktop Outlook app this works perfectly.
On the web version nothing happens. I can't see any communication between the dialog and host page when using Office.context.ui.messageParent() or Office.Dialog.messageChild()
The frontend in the dialog sends a message with the file blob to the parent function in the functionfile. The functionfile should then call addFileAttachmentFromBase64Async() when it receives this message but on the web version I can't see any evidence of this.
I've read it could be to the urls in the in the manifest.xml. Here is ours:
<AppDomains>
<AppDomain>https://outlook.office.com</AppDomain>
<AppDomain>https://outlook.live.com</AppDomain>
<AppDomain>https://localhost:44312</AppDomain>
<AppDomain>https://*.{company}.cloud</AppDomain>
<AppDomain>https://localhost:3001</AppDomain>
</AppDomains>
And here is the simplified section of code that opens the dialog:
Office.context.ui.displayDialogAsync(url, { height: 60, width: 60, displayInIframe: true }, asyncResult => {
if (handleError(asyncResult)) return;
dialog = asyncResult.value;
dialog.addEventHandler(Office.EventType.DialogMessageReceived, processMessage);
const promises = [];
{working business logic}
Promise.all(promises).then(values => {
{working business logic}
event.completed();
});
});
Other issues we have in the web version that might be releavent:
The 'X' close button in the top right of the dialog box does not work. Neither will calls to Office.context.ui.closeContainer() or Office.Dialog.close()
If we set displayInIframe: false then the add-in will immediately close itself upon opening unless we throttle our internet connect. But even when throttling the attaching email process does not work. If I remove the <script type="text/javascript" src="https://appsforoffice.microsoft.com/lib/1.1/hosted/office.js" crossorigin></script> script in the .html then it no longer crashes (but naturally the app needs that)
I have tested this on both Edge and Chrome and they both have this issue. I have not tested on any other browsers
Again, the app works correctly and as expected on the Outlook desktop app. Any help or suggests are appreciated. Thanks.
Just remove the event.completed() call from the callback.
Is it possible to get background_page target for Firefox Add-on in puppeteer?
For testing chrome extensions, I can easily access the background_page when extension is loaded by doing the following:
// Bring up chrome browser with extension loaded
const browser = await puppeteer.launch({
headless: false,
defaultViewport: null,
ignoreHTTPSErrors: true,
timeout: 0,
args: [
`--disable-extensions-except=${CRX_PATH}`,
`--load-extension=${CRX_PATH}`,
'--ignore-certificate-errors',
'--no-sandbox',
'--disable-setuid-sandbox',
'--window-size=1920,1080',
],
});
// Fetch browser targets
const targets = await browser.targets();
// Filter out background_page for extension from the targets
const backgroundPageTarget = targets.find((target) => {
return target.type() === 'background_page';
});
I was able to load my firefox add-on by following these guides:
https://github.com/puppeteer/puppeteer/issues/4162
https://github.com/puppeteer/puppeteer/blob/f26bb7f4c44d9b7db5cc73c4af32db6fa5bcd3a2/experimental/puppeteer-firefox/README.md#add-ons
However, I've been unable to access the background_page of the add-on. I need that to intercept and validate requests and responses made by the add-on.
I managed to make it work with Selenium by following these steps:
Open up the same Firefox browser application that you're making Puppeteer connect to.
Load the extension the same way that you make Puppeteer load it (there's different ways, I did it by loading an unsigned version with Firefox dev edition).
Activate the popup window for the extension, then right click and select View page source.
In the URL, you should see this pattern view-source:moz-extension://<extension-id>/<extension-page-name>.html
Using this extension ID, you can make your script go to the background page by having the browser navigate to moz-extension://<extension-id>/<background-page-name>.html
I need to control Firefox browser via webdriver. Note, I'm not trying to control page elements (i.e. find element, click, get text, etc); rather I need access to Firefox's profiler and force gc (i.e. I need firefox's Chrome Authority and sdk). For context, I'm creating a micro benchmark framework, not running a normal webdriver test.
Obviously raw webdriver won't work, so what I've been trying to do is
1) Create a firefox extension/add-on that does what I need: i.e.
var customActions = function() {
console.log('calling customActions.')
// I need to access chrome authority:
var {Cc,Ci,Cu} = require("chrome");
Cc["#mozilla.org/tools/profiler;1"].getService(Ci.nsIProfiler);
Cu.forceGC();
var file = require('sdk/io/file');
// And do some writes:
var textWriter = file.open('a/local/path.txt', 'w');
textWriter.write('sample data');
textWriter.close();
console.log('called customActions.')
};
2) Expose my customActions function to a page:
var mod = require("sdk/page-mod");
var data = require("sdk/self").data;
mod.PageMod({
include: ['*'],
contentScriptFile: data.url("myscript.js"),
onAttach: function(worker) {
worker.port.on('callCustomActions', function() {
customActions();
});
}
});
and in myscript.js:
exportFunction(function() {
self.port.emit('callCustomActions');
}, unsafeWindow, {defineAs: "callCustomActions"});
3) Load the xpi during my webdriver test, and call out to global function callCustomActions
So two questions about this process.
1) This entire process is very roundabout. Is there a better practice for talking to a firefox extension via webdriver?
2) My current solution isn't working well. If I run my extension via cfx run directly (without webdriver) it works as expected. However, neither the sdk nor chrome authority do anything when running via webdriver.
By the way, I know my function is being called because the log line "calling customActions." and "called customActions." both do print.
Maybe there are some firefox preferences that I need to set but haven't?
It may be that you do not need the add-on at all. Mozilla uses Marionette for test automation of Firefox OS amongst other things:
Marionette is an automation driver for Mozilla's Gecko engine. It can
remotely control either the UI or the internal JavaScript of a Gecko
platform, such as Firefox or Firefox OS. It can control both the
chrome (i.e. menus and functions) or the content (the webpage loaded
inside the browsing context), giving a high level of control and
ability to replicate user actions. In addition to performing actions
on the browser, Marionette can also read the properties and attributes
of the DOM.
If this sounds similar to Selenium/WebDriver then you're correct!
Marionette shares much of the same ethos and API as
Selenium/WebDriver, with additional commands to interact with Gecko's
chrome interface. Its goal is to replicate what Selenium does for web
content: to enable the tester to have the ability to send commands to
remotely control a user agent.
I'm developing a Chrome (packaged) app which maintains a set of bookmarks. This opens in its own small window. Clicking on a bookmark opens it in a browser using a link with target set to '_blank'.
On Mac OS X, these open in Safari. Is there anyway of having them open in Chrome?
When you click on a link with target="_blank" in a packaged app, Chrome respects your choice of the default browser and opens the link externally in whatever it is, not necessarily Chrome. In your case, the default system browser must be Safari.
The easy way to open such links in Chrome would be to make it the default browser instead.
If you don't want to do that, but still for some reason insist that your links open in new tabs specifically in Chrome, here is one (perhaps the only) way to achieve that:
Write a companion extension to your app and have your users install it.
In the app, attach an onclick handler to every link, and use chrome.runtime.sendMessage() to send a request to the extension to open the link's URL (in order to do that, you will have to find out your extension's ID and bake it into its manifest, as described here: http://developer.chrome.com/apps/manifest/key.html):
var link = ...;
link.addEventListener('click', function(e) {
e.stopPropagation();
e.preventDefault();
chrome.runtime.sendMessage(
yourExtensionId, { url: link.href }, function(response) {}
);
};
In the extension, define a chrome.runtime.onMessageExternal(data) handler (it will intercept sendMessage() requests from the app), and use chrome.tabs.create() in there to open a new tab:
chrome.runtime.onMessageExternal.addListener(
function(request, sender, sendResponse) {
// Don't forget to make sure that |sender| is you app here.
chrome.tabs.create({ url: request.url }, function() {
// If you need to notify the app when the tab opens:
sendResponse(true);
});
// 'true' means that your response is sent asynchronously.
return true;
}
);
I created a Firefox extension and chrome extension. In Chrome I am using background.cs, so it will get loaded only once for all Chrome instances, so if I will write simple alert in background it will show alert box only for once.
The same thing is not working with Firefox, it will show that alert message all the times when I will open new Firefox windows.
Is there anything like background in Firefox?
Either write a javascript module or switch to the Add-on SDK
A javascript module would be something like this
this.EXPORTED_SYMBOLS = ["Helper"];
this Helper = {
initialized: false,
init: function() {
if(this.initialized){
return;
}
// code here is executed only the first time init() is called
this.initialized = true;
}
};