I've wanted to try a Chrome Extension for a while, and one thing that always bugged me about Chrome is that clicking on an active mailto: link opens GMail (if it's your handler) in the same tab, navigating away from the page.
When you click on a mailto: link using the Gmail handler, it takes the linked email address and appends it to the Compose window:
https://mail.google.com/mail/?view=cm&fs=1&tf=1&source=mailto&to=youremail#somesite.com
What I want to do is create an extension that gives me a context menu option to compose a new email. I've got the basics down (see below) but I cannot figure out how to get the recipients email address automatically included in the popup.
manifest.json:
"background": {
"scripts": [ "background.js" ]
},
"description": "Creates a context menu option which copies the selected address into a new Gmail compose window.",
"manifest_version": 2,
"name": "New Gmail Window",
"permissions": [ "tabs", "contextMenus" ],
"version": "0.1"
}
background.js
function getEmail(info, tab) {
chrome.windows.create({
url: "https://mail.google.com/mail/?ui=2&view=cm&fs=1&tf=1&shva=1&", // This is the URL I need to figure out.
width: 640,
height: 700,
focused: true,
type: "popup",
})
}
chrome.contextMenus.create({
title: "Send Email",
contexts: ["selection"],
targetUrlPatterns: ["mailto:* "],
onclick: getEmail,
});
You're 99% of the way there. This is the simple fix to get the email address in there:
url: "https://mail.google.com/mail/?ui=2&view=cm&fs=1&tf=1&shva=1&to="+info.linkUrl.substr(7),
info.linkUrl grabs the whole "mailto:someone#domain.com", and the .substr(7) just cuts off the "mailto:" portion.
Additional Notes:
Who wants to have to select (i.e., highlight) the email link? I recommend including links in the context (contexts: ["selection", "link"]).
You have a space at the end of you targetUrlPatterns (["mailto:* "). I'm not sure why it isn't messing anything up on the selections I've tried. But it does mess things up when you add "link" to the contexts to be able to email with just a right-click.
Related
I'm trying to build a somehow dummy Chrome extension. I want it to run only in specific pages, so I'm using a Page Action.
Let's say I want the page action to run on the Instagram website, then (accordingly the docs), I would need something like this on my manifest.json right?
{
"manifest_version": 2,
"name": "Some name",
"version": "0.0.3",
"description": "Some description",
"content_scripts": [
{
"matches": [
"https://www.instagram.com/*"
],
"js": ["content.js"]
}
],
"page_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": ["background.js"]
}
}
while the content script runs only on instagram pages as one would expect, the browser extension is not clickable (gray look, and when I click most options are not clickable).
this makes impossible to act upon extension button click. In my background.js I have:
function click(tab) {
console.log('click from ' + tab);
}
chrome.pageAction.onClicked.addListener(click);
that never gets called.
So, what's wrong that makes impossible to act upon extension click on some pages?
Note: I saw this question/answer, but couldn't find the problem/solution How can I add a click for pageAction?
You have to call pageAction.show in order for your pageAction button to be enabled (clickable).
The pageAction documentation says (emphasis mine):
You make a page action appear and be grayed out using the pageAction.show and pageAction.hide methods, respectively. By default, a page action appears grayed out. When you show it, you specify the tab in which the icon should appear. The icon remains visible until the tab is closed or starts displaying a different URL (because the user clicks a link, for example).
With a manifest.json content_scripts entry
Because you already have a content script that runs on the page you desire to have this function on, probably the easiest way to do this is to have your content script send a message to your background script telling it to show the page-action button for that tab.
Your content script could look something like:
chrome.runtime.sendMessage({type: showPageAction});
Your background script could look something like:
chrome.runtime.onMessage(function(message, sender, sendResponse) {
if(typeof message === 'object' && message.type === 'showPageAction') {
chrome.pageAction.show(sender.tab.id);
}
});
Without a manifest.json content_scripts entry
If you did not have a content script, you would probably want to use a webNavigation.onCompleted listener, or tabs.onUpdated listener, to listen for a change in the tab's URL in order to determine that the page-action button should be shown. Obviously, the trigger for calling pageAction.show() does not have to be the URL which is currently displayed in the tab, but that is the most common.
I am trying to create a context menu option which copies some text to the system clipboard.
Currently, I am just copying a hard-coded string literal, but I am wondering how it could be changed to copy selected text. Specifically, I don't know how to properly create the createProperties object (see bottom)
It is my understanding that this can only be done through a background page.
I have the following background page:
background.html
<textarea id="temp"></textarea>
<script src="context.js"></script>
context.js is as follows:
chrome.contextMenus.create({
"title": "Freedom",
"contexts": ["editable"],
"onclick" : copyToClipboard
});
function copyToClipboard()
{
var tempNode = document.getElementById("temp");
tempNode.value = "some text";
tempNode.select();
var status = document.execCommand('copy',false,null);
if(status) alert('successful');
else alert('unsuccessful');
}
my manifest.json is as follows:
{
"manifest_version": 2,
"name": "Freedom",
"description": "Provides users useful and fun context menu options that they can access from anywhere.",
"version": "1.0",
"permissions": [
"contextMenus",
"clipboardWrite"
],
"background": {
"page": "background.html"
}
}
I am apparently declaring the chrome.contextMenus.create() function incorrectly. I have read the docs for it and I can only imagine that I am not properly creating the createProperties object.
I have been trying to mimic these sources:
Is that possible calling content script method by context menu item in Chrome extension?
http://paul.kinlan.me/chrome-extension-adding-context-menus/
some other related questions are:
Copy to Clipboard in Chrome Extension
How to copy text to clipboard from a Google Chrome extension?
"createProperties" in the documentation is the dictionary that is passed to the chrome.contextMenus.create method (i.e. that thing with "title", "contexts", etc.)
The onclick event description of chrome.contextMenus.create states that the function receives two parameters. The first parameter ("info") is a dictionary with information about the selected text. The second parameter ("tab") contains information about the tab (in your case, you don't need though).
The "info" dictionary has a property "selectionText" that holds the selected text when the context menu item was clicked. This can be used in your code as follows:
function copyToClipboard(info) {
var tempNode = document.getElementById("temp");
tempNode.value = info.selectionText; // <-- Selected text
tempNode.select();
document.execCommand('copy', false, null);
}
That would solve your immediate question.
Besides that, your extension can be improved by converting your background page to an event page. The main benefit of event pages over background pages is that your extension will not unnecessarily use memory while sitting idle in the background.
// background.js
// Register context menu
chrome.runtime.onInstalled.addListener(function() {
chrome.contextMenus.create({
"id": "some id", // Required for event pages
"title": "Copy selected text to clipboard",
"contexts": ["editable"],
// "onclick" : ... // Removed in favor of chrome.contextMenus.onClicked
});
});
// Register a contextmenu click handler.
chrome.contextMenus.onClicked.addListener(copyToClipboard);
Here is a minimal manifest.json (note the "persistent": false key, which specifies that you want to use an event page)
{
"manifest_version": 2,
"name": "Copy selected text to clipboard",
"version": "1.0",
"permissions": [
"contextMenus",
"clipboardWrite"
],
"background": {
"page": "background.html",
"persistent": false
}
}
I have a working extension that allows me to check market prices of steam items.
You basically click the extension and then a prompt box opens and the item is inputted there.
It then opens up a new windows with the search query, displaying the market prices.
I would like to tweak it by displaying the list of items as a popup from the extension, like the default popup.
For that I need to know some stuff:
1) How do I call that popup function within the js code?
2) How do I open it so that it shows only what I need? like this, instead of showing the whole site.
Here are the codes:
manifest:
"manifest_version": 2,
"name": "CS:GO checker",
"description": "This extension checks market prices",
"version": "1.1337",
"permissions": [
"http://steamcommunity.com/market/"
],
"browser_action": {
"default_icon": "icon.png"
},
"background": {
"scripts": ["popup.js"],
"persistent": false
}
popup.js:
function test ()
{
var userInput=prompt("Please enter your item below:");
if (userInput!=null)
{
newwindow=window.open("http://steamcommunity.com/market/search?q="+userInput,userInput,'height=800,width=670');
if (window.focus) {newwindow.focus()}
return false;
}
}
chrome.browserAction.onClicked.addListener(test);
Thanks in advance!
edit: I forgot to mention that I'm very new to javascript, so if you have an answer, try to explain it very carefully to me that I could understand.
I'm trying to create a chrome extension. When the user clicks my extension's icon (browserAction) the content script appends an extra div to the body of the open page(current tab). It works fine in all the sites except google's search page and youtube. I'm not getting any error message or anything. It simply wont give any response.
This is my code in content.js:
alert('sdsd');
$('body').append("<div id='popup'>My extension name</div>");
I've put the alert for testing purpose. So when extension is toggled it should show an alert message followed by appending the div to body, ideally! But it wont for these 2 sites.
Any idea what could be going wrong here?
manifest
{
"name": "My first extension",
"version": "1.0",
"background": { "scripts": ["background.js"] },
"content_scripts": [{
"all_frames": true,
"css": ["style.css"],
"matches": ["http://*/*","https://*/*"]
}],
"permissions": [ "tabs","http://*/*" ],
"browser_action": { "name": "test" },
"manifest_version": 2
}
background.js
chrome.browserAction.onClicked.addListener(function(tab){
chrome.tabs.executeScript(null,{file:"jquery.min.js"},function(){
chrome.tabs.executeScript(null,{file:"content.js"});
});
});
In Youtube's page, $ is overwritten and isn't jQuery. It's
bound: function ()
{
return document.getElementById.apply(document, arguments)
}
So your code makes an exception as there document.getElementById('body') is undefined.
You should try using noConflict().
EDIT :
Why aren't you simply listing jQuery.min.js and your content.js in the content_scripts instead of injecting them programmatically. This would avoid conflicts.
EDIT 2 :
Now that you use content scripts, you should use communication as described here to send from background.js to the content script the instruction to show the alert.
EDIT 3 :
Another solution would have been to use programmatic injection (as you initially did) and not use jquery, $('body').append("<div id='popup'>My extension name</div>"); being translated in vanilla JS to
var div = document.createElement('div');
div.id = 'popup';
document.body.appendChild(div);
document.getElementById('popup').innerHTML = "My extension name";
But it's generally cleaner (and requires less permissions) to avoid programmatic injection.
I am writing a Chrome extension, and I want a login window to be popped up when users click on the context menu so that user can input username and password. In Chrome extension, I only found chrome.pageAction.setPopup and chrome.browserAction.setPopup can be used to show popup windows, but they show popups only when the page action's icon or browser action's icon is clicked, not the context menu. Of course, I can use javascript prompt box to do this, but the problem is the password cannot be masked in the prompt box. So I am wondering if there are some other ways to create a popup window in Chrome extension.
Thanks!
Pick and choose:
showModalDialog(<String url> [, <object arguments>])
Opens a dialog-like window, in which you can load a page within your chrome extension. HTML can be used.
Do not use showModalDialog, it is going to be removed from Chrome.
window.open(<String url> [, <String window_name>[, <String windowFeatures>]])
Opens a window, which, unlike the previous method, does not appear as a dialog. The user can minimize the window, and continue with something else.
chrome.windows.create(<object createData [, <function callback>]>)
(Specific to Chrome extensions) Create a new window, with given arguments (size, url, position, ...).
All of these methods allows you (your extension) to open a new window/dialog, and handle the logic from that page. This page should be packaged with your extension.
See Message passing to pass the entered data to your extension.
Demo
Tabs within your extension have direct access to the background page using chrome.runtime.getBackgroundPage. I'll demonstrate this feature in this demo, as well as a conventional way of message passing:
manifest.json
{
"name": "Dialog tester",
"version": "1.0",
"manifest_version": 2,
"background": {
"scripts": ["background.js"],
"persistent": false
},
"content_scripts": [{
"matches": ["<all_urls>"],
"js": ["open-dialog.js"]
}]
}
background.js
// Handle requests for passwords
chrome.runtime.onMessage.addListener(function(request) {
if (request.type === 'request_password') {
chrome.tabs.create({
url: chrome.extension.getURL('dialog.html'),
active: false
}, function(tab) {
// After the tab has been created, open a window to inject the tab
chrome.windows.create({
tabId: tab.id,
type: 'popup',
focused: true
// incognito, top, left, ...
});
});
}
});
function setPassword(password) {
// Do something, eg..:
console.log(password);
};
open-dialog.js
if (confirm('Open dialog for testing?'))
chrome.runtime.sendMessage({type:'request_password'});
dialog.html
<!DOCTYPE html><html><head><title>Dialog test</title></head><body>
<form>
<input id="pass" type="password">
<input type="submit" value="OK">
</form>
<script src="dialog.js"></script>
</body></html>
dialog.js
document.forms[0].onsubmit = function(e) {
e.preventDefault(); // Prevent submission
var password = document.getElementById('pass').value;
chrome.runtime.getBackgroundPage(function(bgWindow) {
bgWindow.setPassword(password);
window.close(); // Close dialog
});
};
Documentation for used methods
chrome.runtime.sendMessage(<request>, <function callback>) and chrome.runtime.onMessage.addListener(<function listener>)
chrome.extension.getURL(<String path>)
chrome.runtime.getBackgroundPage(<function callback>)
chrome.tabs.create(<object createData> [, <function callback>])
chrome.windows.create(<object createProperties> [, <function callback>])