I'm making add-on modules for several browsers, including Chrome and Firefox.
I just did what I want with Chrome : overriding new tab url to load a HTML file with the manifest.json. Pretty simple. (Now I'm able to copy paste again :)) :
...
"chrome_url_overrides" : {
"newtab": "override.html"
},
...
When the user create a new blank tab, it overrides the default page and loads the file I want : override.html, with the same behavior (no URL in the address bar).
But now, I want to do the same thing with Firefox using Add-on SDK. I tried using browser.newtab.url :
var { get, set } = require("sdk/preferences/service");
var { when: unload } = require("sdk/system/unload");
var oldValue = get("browser.newtab.url");
set("browser.newtab.url", 'http://www.example.com');
// Restore old setting when unload
unload(function() {
set("browser.urlbar.autoFill", oldValue);
});
It works, but I really would be able to load an HTML file instead giving it a new URL (the code would be more maintainable) and keep a clean address bar.
Any ideas ?
Related
This is for Windows.
I have a flash application I am converting to AIR. I built a captive installer using NSIS and it works fine. However I would like to have an icon on a website which checks if the application is already installed and ask the user if they wish to run it. If it is not installed, they get the option to download it.
I am fairly certain this is doable, because Zoom and GoToMeeting both do this.
My searching skills seem to be failing me when looking for this.
Edit:
It appears the best/only way to do this is to create a custom protocol for the application. Something like DoDaApp://.
Which brings up the next set of questions;
How to create an NSIS file which will create the appropriate registry entries on the client computer? As a user, not admin.
How to check if the protocol is currently installed on the computer?
This is a partial answer as it does not work in Edge. I'll explain the issue below.
As recommended in How to detect browser's protocol handlers you can use timeout & blur event handlers. Here is my interpretation of the code;
function checkCustomProtocol(inProtocol,inInstalLink,inTimeOut)
{
var timeout = inTimeOut;
window.addEventListener('blur',function(e)
{
window.clearTimeout(timeout);
}
)
timeout = window.setTimeout(function()
{
console.log('timeout');
window.location = inInstalLink;
}, inTimeOut
);
window.location = inProtocol;
}
Microsoft Edge is ever so helpful by popping up a dialog box telling you "You'll Need a new app to open this" which "blurs" the screen, not allowing download of the file.
So I will be posting another question on how to make it work in Edge. I have reviewed ismailhabib's code but the known issues section says it doesn't work with Edge either.
Here is a more complete answer. It has been lightly tested in IE 11, Microsoft Edge, Chrome and Firefox. I also added comments;
/*
checkCustomProtocol - check if custom protocol exists
inProtocol - URL of application to run eg: MyApp://
inInstallLink - URL to run when the protocol does not exist.
inTimeOut - time in miliseconds to wait for application to Launch.
*/
function checkCustomProtocol(inProtocol,inInstalLink,inTimeOut)
{
// Check if Microsoft Edge
if (navigator.msLaunchUri)
{
navigator.msLaunchUri(inProtocol, function ()
{
//It launched, nothing to do
},
function()
{
window.location = inInstalLink; //Launch alternative, typically app download.
}
);
}
else
{
// Not Edge
var timeout = inTimeOut;
//Set up a listener to see if it navigates away from the page.
// If so we assume the papplication launched
window.addEventListener('blur',function(e)
{
window.clearTimeout(timeout);
}
)
//Set a timeout so that if the application does not launch within the timeout we
// assume the protocol does not exist
timeout = window.setTimeout(function()
{
console.log('timeout');
window.location = inInstalLink; //Try to launch application
}, inTimeOut
);
window.location = inProtocol; //Launch alternative, typically app download.
}
}
I work with SAAS offering (ServiceNow) with 5 different environments. I find myself frequently switching environments where the only difference is the base URL.
I've never done any plug-in work so I'm not sure if this is feasible but I'd like to set my a few base URL presets and be able to take the current URL and just swap the base with a click of a button.
It's totally possible.
The pointer in general direction is the chrome.tabs API: you'll be able to manipulate a tab's URL with it.
UI-wise, you get a button on the toolbar called a Browser Action; you can simply do something when you click on it, or you can have a small UI page drop down from it. You may also be interested in chrome.commands API to add keyboard shortcuts.
Here's a mock for the simplest architecture possible: a background script that swaps between 2 base domains on click (note that it needs "activeTab" permission).
var BASE1 = "example.com";
var BASE2 = "example.org";
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function baseToRegExp(base) {
return new RegExp("^(https?:\/\/[^\/]*)(" + escapeRegExp(base) + ")/");
}
var BASE1RegExp = baseToRegExp(BASE1);
var BASE2RegExp = baseToRegExp(BASE2);
chrome.browserAction.onClicked.addListener(function(tab) {
if (tab.url.match(BASE1RegExp)) {
chrome.tabs.update(tab.id, {
url: tab.url.replace(BASE1RegExp, "$1"+BASE2+"/")
});
} else if (tab.url.match(BASE2RegExp)) {
chrome.tabs.update(tab.id, {
url: tab.url.replace(BASE2RegExp, "$1"+BASE1+"/")
});
}
});
There are many beginner tutorials for Chrome Extensions; I would recommend starting at the Overview page.
This is my first time learning to build a firefox addon. I want store all the open tabs in a window and for that I require sdk/tabs.
Here is my js file:
/*
Given the name of a beast, get the URL to the corresponding image.
*/
debugger;
var tabs = require("sdk/tabs");
function beastNameToURL(beastName) {
switch (beastName) {
case "Save Session":
debugger;
for (let tab of tabs)
console.log(tab.url);
return;
case "Load Session":
debugger;
return chrome.extension.getURL("beasts/snake.jpg");
case "Turtle":
return chrome.extension.getURL("beasts/turtle.jpg");
}
}
/*
Listen for clicks in the popup.
If the click is not on one of the beasts, return early.
Otherwise, the text content of the node is the name of the beast we want.
Inject the "beastify.js" content script in the active tab.
Then get the active tab and send "beastify.js" a message
containing the URL to the chosen beast's image.
*/
document.addEventListener("click", function(e) {
if (!e.target.classList.contains("btn")) {
return;
}
var chosenBeast = e.target.textContent;
var chosenBeastURL = beastNameToURL(chosenBeast);
chrome.tabs.executeScript(null, {
file: "/content_scripts/beastify.js"
});
chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
chrome.tabs.sendMessage(tabs[0].id, {beastURL: chosenBeastURL});
});
});
When I reach the var tabs = require("sdk/tabs") line I get a Reference error.
Github : https://github.com/sagar-shah/Session-manifest
Kindly let me know how do I resolve this error. This being my first time with add-ons I am completely lost.
Thanks in advance.
Update:
Tried to declare it globally in the js file. Now I am getting undefined error for tabs.
Update2:
I was mixing up development using sdk and webextensions as pointed out by #matagus. I have decided to go with development using the webextensions. Link to the new repository has been updated.
The error is on package.json line 6: you're telling to the addon sdk that the main file of your addon is manage.json. According to [the docs] the value of main should be:
A string representing the name of a program module that is located in one of the top-level module directories specified by lib. Defaults to "index.js".
So you need to change its value to index.js.
Besides that, I think you're missing a difference between Firefox addon built using the addon-sdk (which do not have a ´manifest.json´ and that you build using jpm tool) and the new WebExtensions which do require you to write a ´manifest.json´ like the one already have.
UPDATE:
Again: you're missing the difference between WebExtensions and SDK-based addons. Now you made a WebExtension but you're trying to use the SDK. It isn't possible. Just use chrome.tabs directly instead of trying to import it from the sdk (var tabs = require("sdk/tabs");).
I developed a google chrome extension that works good with Windows OS. but the problem that does not work with mac, I tried to check the problem, I found that function
chrome.tabs.executeScript
does not work on mac, this is the completely code that worked good with windows not mac.
// The onClicked callback function.
function onClickHandler(info, tab) {
// the problem in injecting code
chrome.tabs.executeScript
( null,{code:"var activeElm = document.activeElement; var inp_text = activeElm.value; console.log(activeElm.value);"});
};
chrome.contextMenus.onClicked.addListener(onClickHandler);
// Set up context menu tree at install time.
chrome.runtime.onInstalled.addListener(function() {
// Intentionally create an invalid item, to show off error checking in the
// create callback.
console.log("About to try creating an invalid item - an error about " +
"duplicate item child1 should show up");
chrome.contextMenus.create({"title": "consoleMe", "id": "child523", "contexts":["selection"]}, function() {
if (chrome.extension.lastError) {
console.log("Got expected error: " + chrome.extension.lastError.message);
}
});
});
Hint:
I use content_scripts injection files in the manifest file, but it seems did not activated on Google chrome on Mac.
"content_scripts": [
{
"matches": ["http://*/*","https://*/*"],
"js" : ["jquery.min.js","fix.js","injscript.js"],
"all_frames": false
}
],
OS : Mac 10.8 Mountain lion --
Google Chrome V 32
There should be no difference between Windows and Mac. It's likely that something else is different between your two setups.
It's not clear to me whether the javascript snippet above is a background script or an injected content script. Can you provide the full manifest and indicate which file the snippet belongs to?
If it's a background script, chrome.tabs.executeScript with null tabId will apply to the background page, which is not what you expect. Instead, pass tab.id for the tabId.
If it's a content script, the contextMenus API calls won't work because content scripts are not allowed to use chrome APIs (see https://developer.chrome.com/extensions/content_scripts.html).
I want to create an extension that redirects the user to another website if he clicks on the extension button. So far I have only seen extensions which create a new tab for each click.
Is it possible to redirect the user to another website using the active tab?
I tried something like this:
chrome.browserAction.onClicked.addListener(function(tab) {
var url = "https://www.mipanga.com/Content/Submit?url="
+ encodeURIComponent(tab.url)
+ "&title=" + encodeURIComponent(tab.title);
document.location.href = url; // <-- this does not work
});
Attention: If you develop cross-browser extensions (I hope you do!), I recommend that you use chrome.tabs.query(). Please see Jean-Marc Amon's answer for more information. This answer still works in both Firefox and Chrome, but query() is more commonly used, has more options, and works in background pages and popup views.
From the chrome.tabs API, you can use getCurrent(), query(), or update().
Right now, I prefer update() as this allows you to update the current tab without needing to do much else.
NB: You cannot use update() from content scripts.
If updating the url from a content script is required then you should look to use query instead. Jean-Marc Amon's answer provides a wonderful example of how to get the active tab in this case (don't forget to upvote him!).
update()
let myNewUrl = `https://www.mipanga.com/Content/Submit?url=${encodeURIComponent(tab.url)}&title=${encodeURIComponent(tab.title)}`;
chrome.tabs.update(undefined, { url: myNewUrl });
Here, we have set the first argument of update to undefined. This is the tab id that you're wanting to update. If it's undefined then Chrome will update the current tab in the current window.
Please see Domino's answer for more information on update and also note that undefined is not needed. Again, please don't forget to upvote their answer as wellif you find it useful.
getCurrent()
getCurrent also cannot be called from a non-tab context (eg a background page or popup view).
Once you have the current tab, simply pass update().
chrome.tabs.getCurrent(function (tab) {
//Your code below...
let myNewUrl = `https://www.mipanga.com/Content/Submit?url=${encodeURIComponent(tab.url)}&title=${encodeURIComponent(tab.title)}`;
//Update the url here.
chrome.tabs.update(tab.id, { url: myNewUrl });
});
NB: In order to use this this functionality, you must ensure that you have the tabs permission enabled in your manifest.json file:
"permissions": [
"tabs"
],
You can use chrome.tabs.query too
chrome.tabs.query({currentWindow: true, active: true}, function (tab) {
chrome.tabs.update(tab.id, {url: your_new_url});
});
The chrome.tabs.update method will automatically run on the current active tab if no tab id is passed.
This has the added advantage of not requiring the tabs permission. Extensions with this permission warn the user that they can read the browsing history, so you should avoid asking for it if you don't need to.
Changing the current tab's URL is as simple as writing this:
chrome.tabs.update(undefined, {url: 'http://example.com'});
Or as mentionned by farwayer in the comments, you don't need to put two arguments at all.
chrome.tabs.update({url: 'http://example.com'});
The answers given here no longer work: the Chrome Tabs API can no longer be used by content scripts, only by service workers and extension pages.
Instead, you can send a message to a service worker to get it to update the location of the current tab: see https://stackoverflow.com/a/62461987.
See this for a simple working example.