I want to make a left-click menu. How can I make it on my Chrome extension?
This is my right-click menu:
chrome.runtime.onInstalled.addListener(function() {
chrome.contextMenus.create({
title: 'Dolar',
id: 'dolar',
contexts: ['all'],
});
});
chrome.contextMenus.onClicked.addListener(function(info, tab) {
if (info.menuItemId === "dolar") {
alert("Hello");
}
});
For making it left-click, how do I change it?
There is no special Chrome extension API to create a menu that opens on left-click. To make a menu that opens on left-click, you will need to inject a content script in any page in which you desire to have it used. In that content script you will need to listen for the click event with the left button. You will then need to insert into the DOM the elements that make up your menu. You will need to do all of this manually, or find a library which will abstract the problem.
In general, this will be inconsistent with the user interface which is used on most machines. This will be counter to most user's expectations and may cause user confusion. In addition, web pages will expect to be able to use left-click for whatever purpose they desire, if any, beyond the normal clicks on links (e.g. activating drop-down/pop-out menus, etc.). Your use of it will conflict with using left-click for any interaction within the page. Unless you have a specific use case, having a left-click menu that is generally available is probably a bad idea.
Having a UI element which opens a menu when the user left-clicks on it is a different situation. In such case, the user is clicking on a UI element which is expected to do something. However, you should consider carefully if loading a UI into every page is appropriate. Sometimes it is. Doing so can place a heavy burden on pages where your add-on is completely unused. You can minimize this impact by loading just the minimal amount into the page to show the beginning of the UI. Then, loading the rest of your code/libraries/UI only when the user begins interacting with your extension's UI. Needing a UI in the page is much more likely to be the case when your extension is for a limited set of pages (i.e. modifying the UI on a particular domain/page). However, for most extensions, general interaction with your add-on will begin with a browser/page action button click, a hotkey, a context menu entry, or your add-on detecting something and opening a UI for the user (i.e. not through adding a full UI to every page).
Related
I know how to show a panel with position:button. But, when I try to show() an additional panel, the previous panel disappears.
I don't want to disable auto hide. But I want to show 2 panels at the same time.
So how do I show both at the same time?
Code:
function handleChange(state) {
if (state.checked) {
panelf.show({
position: {
bottom: 20
}
});
panel.show({
position: button
});
}
}
The Add-on SDK prevents more than one sdk/panel from being open at a time:
You can not do exactly what you are wanting to do. The sdk/panel API specifically prevents more than one sdk/panel from showing at a time. That is one sdk/panel open at a time across all Add-on SDK based extensions loaded in that profile. In other words, if some other Add-on SDK based extension opens a panel, yours will close. There is no way to disable this using stock Add-on SDK code. This is explicitly stated in the sdk/panel documentation (part of the last paragraph in the Usage section):
Opening a panel will close an already opened panel.
To make it more clear that this restriction is across all Add-on SDK extensions, I have updated the text to be:
Opening a panel will close any panel created by the Panel() constructor that is already open, even if that panel was opened by a different Add-on SDK based extension.
When you create a panel using the Panel() constructor a listener is attached to the panel using a call to a private function, setupAutoHide(this);. In part, the setupAutoHide() is [permanent links for those in this paragraph to the code as it was when this answer was written: Panel(), setupAutoHide(this); setupAutoHide().]:
// Utility function takes `panel` instance and makes sure it will be
// automatically hidden as soon as other panel is shown.
var setupAutoHide = new function() {
let refs = new WeakMap();
return function setupAutoHide(panel) {
// Create system event listener that reacts to any panel showing and
// hides given `panel` if it's not the one being shown.
As you should be able to tell from the comments in this code, it is specifically designed to prevent what you desire to do (showing more than one sdk/panel at a time).
Alternate methods to show content:
To provide detailed suggestions as to how to accomplish what you desire for your user interface, we are going to need more information as to what you are wanting to do with the two sdk/panels.
Given that you have not described the reason you desire to have more than one sdk/panel open at one time, I have to guess. One reason that you might want to leave an sdk/panel open while using another as a drop-down panel to a sdk/ui/button/toggle is that you are using the first one as a semi-permanent display of information or a dialog. In such case, you should be using a different UI methodology to display that information. There are multiple possibilities of how to do that depending on what you want your UI to look like. One possibility is to implement a ui/frame.
Another possibility is to use openDialog() (or open()) from window/utils to open a dialog window. These dialog windows are completely separate windows which can exist as long as you desire. If desired, it could be styled to be nearly identical in appearance to an sdk/panel. How tightly coupled it is with the current page or window depends on the programming that you do.
The Add-on SDK implements sdk/panels as XUL popups. There is no restriction within Firefox on displaying more than one XUL popup at a time. You could create these yourself within the primary Firefox DOM rather than using the Panel() constructor.
Yet other possibilities include: implementing your first sdk/panel as a different portion of either the main window UI or as part of the content page; alternately, the drop-down sdk/panel could be implemented as a an actual drop-down menu, a <menupopup>, which can either be an actual menu, or have arbitrary content using a <panel>. If you really desired, you could code it to display exactly as if you had used the Panel() constructor. However, those latter possibilities go around the Add-on SDK and will potentially result in your add-on requiring more on-going maintenance if the underlying structure of Firefox is changed.
There are way too many possibilities as to how to implement what you might desire for your UI to cover here. This is particularly the case because we do not know what the goals are of what you are attempting to implement with your UI.
How can a chrome extension click on a button on active page?
There is banal page on the Web. There is simple element of button type with specific ID on the page. Also there is Chrome extension with a button. I'd like to click to extension button and the button in turn clicks to page button.
var someElement = document.getElementById('someElement');
someElement.addEventListener('click', function () {
// here I'd like to click on a button with specific ID.
});
The very first thing you want to do is to read the Overview page, especially the Architecture part. Read it thoroughly, and it will answer many questions you have.
Your problem can be split into two parts.
How to trigger something with a click on your extension.
How to click something inside the active tab.
Before I proceed, I'll reiterate what wOxxOm said: there's a great small example in the docs that does nearly what you want. But if you want to be someone taught to fish, not given a fish, read on.
How to trigger something with a click on your extension
It depends on what kind of UI you're using; the simplest is a Browser Action button.
Simplest button:
If you add a browser action to the manifest without specifying a popup:
"browser_action": {
"default_icon": { "38": "icon38.png" }
},
then clicking on it will raise chrome.browserAction.onClicked event to your extension's pages. The only page open at any time you need it is a background page, the role of which is usually the central dispatch for extension events. So, you need a background page that listens to that event:
"background": {
"scripts": ["background.js"]
},
and
// background.js
chrome.browserAction.onClicked.addListener(function(tab) {
// Okay, the actual action should go here
// And look, we already have the required Tab object for free!
});
Variations (exercises for the reader):
If you do specify a "default_popup" in your manifest, then chrome.browserAction.onClicked will not trigger. Instead, a small popup page will open with the HTML file you specify; you can add UI/logic there as you wish, the principle will be the same as normal webpages but with Chrome API access, except:
You'll need to query for the current tab yourself.
You'll need to be mindful of Chrome's extension CSP.
In case you run into problems, you need to know how to debug them.
If your extension targets only a few specific pages, consider using Page Actions instead of Browser Actions.
As noted in the documentation, Event pages are preferable to Background pages. In this case, you can use an Event page easily without any side effects, but in general this may require some thinking.
You could inject your own UI into the page itself with Content scripts; this is an advanced topic and will not be covered here.
How to click something inside the active tab
Since you've read the Architecture overview, you already know that the only part of the extension that can interact with the DOM of an open page is a Content script.
Content scripts can either be specified in the manifest (and then they will automatically be injected and ready for you when a matching page is opened), or they can be manually injected into the page.
In your case, you want to do something simple, and only when clicked. This is a perfect job for programmatic injection, so we'll stick with that.
Assuming the solution from the previous section, you are in a context of a background page and already have the current tab as the tab variable:
// background.js
chrome.browserAction.onClicked.addListener(function(tab) {
// Do something with tab
});
Programmatic injection is done with chrome.tabs.executeScript method. At a minimum, you need to specify the tab you want to inject to, and the code that will be run:
// background.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(tab.id, {
code: "document.getElementById('#specificId').click()"
});
});
That's not all yet though. The extension must have permissions to execute code in an open tab.
You could use "host permissions" that are defined by a match pattern to give access to specific pages, but remember that we are only triggering it when the user clicks the extension.
For that specific case, there's a special permission "activeTab". It is sufficient to do a lot of things with the currently active tab when the extension is explicitly invoked, and clicking its button is explicit enough.
So, add to manifest:
"permissions": ["activeTab"],
And that should be all you need for this to work.
Extra credit:
While not necessary for this simple purpose, you may want more complicated code than a single line to be executed in the tab. Then it makes sense to use a separate file and invoke executeScript with "file" instead of "code".
Just triggering a click on a button does not require you to directly interact with JavaScript running in the page itself, as DOM events are shared. However, it's important to understand that normally, content scripts can't interact with the page's own scripts, which is called "isolated world". There are ways to bypass it if you really need it, but it's an advanced topic better explained elsewhere.
Sometimes you need the content script to persist, answer some commands and maybe send its own queries to the extension's pages. In that case, it's probably better to auto-inject through the manifest and use Messaging instead of executeScript.
I'm a writing a chrome extension that allows users to do the following:
Load data into the popup when the icon is clicked
Change the data in the popup based on actions the user takes on the page
Append elements to the DOM of the page based on actions taken in the popup
It seems that I can accomplish 1 with a script in the browser_action field of the manifest, but perhaps I need a page_action script for 2 and 3?
The core of the problem is that I do not know exactly how browser_actions and page_actions differ from each other. My limited understanding is that page actions allow data populated in the popup to be manipulated dynamically. Is this true? I cannot find an explanation about the differences that makes sense to me.
Browser Action is a type of extensions that use icon on the right of address bar. You click on that icon and popup page is loading. Those extensions work regardless of page currently opened.
Page Action only works while certain webpage(s) is opened. It displays as an icon inside the address bar (near page URL). This is for extensions only working on certain websites.
If you want to make your extension working on every website, you should use browser_action.
For further information you may want to visit these pages:
http://developer.chrome.com/extensions/browserAction.html
http://developer.chrome.com/extensions/pageAction.html
I'm producing a page which will most often be opened via an anchor with target="_blank".
Progressive enhancement AJAXes in the page and places it within a modal, in which case the close button removes the modal node from the tree — in these situations a 'pop out' link will feature, allowing the user to open the page in a separate window (as above). It's easy enough to figure out whether this should be displayed or not based on the tree structure:
.modal a.pop-out {
display: none;
}
In both these situations, a close link is also appropriate in the same context: because the user journey has taken a momentary detour, it's expected that the user will sooner or later want to close the window and return to the opening window. However, I can't work out what feature detection to use to determine whether or not the link should be displayed. Obviously javascript support is necessary, but if the link was opened independently and javascript is supported, the close button is not appropriate (window.close() will have no effect).
My question the, is how I can work out, without executing it, whether window.close is possible in the current context.
Check if the window has an opener. The modal won't; the new window will.
https://developer.mozilla.org/en-US/docs/Web/API/window.opener
I have a document that can not be quit without saving changes. I use onbeforeunload to ask user if he really wants to quit. It works fine if the "quitting" scenario is clicking on a link and reloading page. but i have also JS menu that moves user from document editor to settings and it's done without website redirect but is handled wholly by JS by replacing "document view" and showing "edit settings view". But moving to edit settings view makes the changes in document unsaved like a normal reload does. So how to invoke browser to ask if user really wants to move to edit settings view like it does when page reload occurs in this scenario?
You can't, without navigating away from the page. But you can ask them with a much nicer, more friendly modal dialog of your own (an absolutely positioned div with a zIndex greater than any other, possibly with an iframe shim under it to eat all clicks, etc.). You can roll your own, but there are lots of modal dialog libraries out there which would save you time.
Or if you like, you can use confirm, which doesn't have a very good user experience (but then, neither does onbeforeunload) but is dead easy to code and entirely cross-browser compatible (despite the link being to a Mozilla page).