Chrome Extension - Dynamic Right-Click Menu - javascript

I am trying to create an option in the right-click menu that is dynamic based on the user's action. If the user selects some text, then right-clicks, the option will say "Display It". If the user right-clicks without selecting some text, the option will say "Select Some Text First" and be grayed out. I am wondering how do I achieve this?
I currently have it so that the option will appear only when the user has selected some text. I am unsure how to modify it to meet my second requirements.
chrome.contextMenus.create ({
title:"Display It!", contexts:["selection"], onclick:function(info,tab) {
chrome.tabs.sendRequest(
tab.id,
{callFunction: "displaySidebar", info: info},
function(response) {console.log(response);}
);
}
});

You cant grey an item out...Chrome has gone to a bit of effort to only make context menu items appear when its relevant which is why i guess theres no grey out option. Your way goes against what Chrome have tried to implement and I think you really should rethink the way you go about this.
Saying that, you can use the chrome.contextMenus.update to change a menu item.
The following code is about as good as your going to get it your way (seriously, rethink this idea)....
function selectedTrueOnClick(info, tab) {
chrome.tabs.sendRequest(
tab.id, {
callFunction: "displaySidebar",
info: info
}, function(response) {
console.log(response);
});
}
function selectedFalseOnClick(info, tab) {
//
}
var contextMenuID = chrome.contextMenus.create({
title: "Select some text",
contexts: ["all"],
onclick: selectedFalseOnClick
});
function contextMenuUpdate(selected) {
if (selected) chrome.contextMenus.update(contextMenuID, {
title: 'You selected "%s"',
contexts: ["all"],
onclick: selectedTrueOnClick
});
else chrome.contextMenus.update(contextMenuID, {
title: "Select some text",
contexts: ["all"],
onclick: selectedTrueOnClick
});
}
contextMenuUpdate(false);

I was looking to accomplish the same thing as the original post, and was able to get it working using some message passing. Regardless of whether it's bad practice or not, I used the enabled(true/false) contextMenu property to leave my context menu option present, but grayed out.
I created a context menu. The important property is the id. The rest is mostly arbitrary because it will be changed dynamically.
In content.js
//This event listener will determine if the context menu should be updated
//based on if the right-button was clicked and if there is a selection or not
document.addEventListener("mousedown", function(event){
if (event.button !== 2) {
return false;
}
var selected = window.getSelection().toString();
if(event.button == 2 && selected != '') {
//get selected text and send request to bkgd page to create menu
chrome.runtime.sendMessage({
'message': 'updateContextMenu',
'selection': true});
} else {
chrome.runtime.sendMessage({
'message': 'updateContextMenu',
'selection': false});
}
}, true);
In background.js:
//add a message listener that will modify the context menu however you see fit
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
if (request.message == 'updateContextMenu') {
if (request.selection) {
chrome.contextMenus.update('contextMenuId',{
'title': 'New Title',
'enabled': true,
"contexts": ["all"],
'onclick': someFunction
});
} else {
chrome.contextMenus.update('contextMenuId',{
'title': 'Select some text first',
'enabled': false,
"contexts": ["all"]
});
}
} else {
sendResponse({});
}
});
//The original context menu. The important property is the id. The rest is mostly
//arbitrary because it will be changed dynamically by the listener above.
chrome.contextMenus.create({
'id': 'contextMenuId',
'enabled': false,
'title': 'Some Title',
"contexts": ["all"]
});

Related

chorme extension - How to replace user selected text

I'm working on a translate chrome extension. I want to get the user selection and translate it after the user click on a context menu voice. I've implemented this code but not work as expected. I've tested it on instagram and seems working into the DM input field. The same code will not work as expected with facebook text input for messages or status textarea. How I can manage the selected text replacing after that it's translated?
background.js
const processSelection = (info, tab) => {
axios({
method: 'GET',
url: 'https://translate.googleapis.com/translate_a/single',
params: {
client: 'gtx',
sl: 'auto',
tl: 'en',
dt: 't',
q: info.selectionText
}
}).then( (res) => {
browser.tabs.sendMessage(tab.id, {translation: res.data[0][0][0]});
});
}
browser.contextMenus.create({
id: 'selection-translate',
title: 'Translate selection',
contexts: ['editable','selection']
});
browser.contextMenus.onClicked.addListener(processSelection);
content-script.js
browser.runtime.onMessage.addListener( (message) => {
console.log(message);
const selectedText = window.getSelection();
const range = selectedText.getRangeAt(0);
console.log(range);
// I've tried to use deleteContents() but without selecting the node it will not work
range.selectNodeContents(range.commonAncestorContainer);
range.deleteContents();
// sometimes the text is appended outside the text input/textarea if selectNodeContents isnt used
range.insertNode(document.createTextNode(message.translation));
});
Another doubt I have is about context menu. If I want to add some submenu to the main one, how I will handle the click event?I want to give the user the ability to select the destination language with other context menus, but not sure how to proceed.
Thank you for the help.

NodeJS: How to re-display custom CLI menu after executing corresponding functionality

I come from a low-level programming background, so JS and NodeJS are a new realm for me.
I am trying to create an application that begins by displaying a CLI menu to the user. Upon the user selecting a menu option, a corresponding functionality will be carried out. Once that functionality completes, I want the menu to be re-displayed.
A very simple way of handling this in Python and embedded C is to enclose the menu in a while(1) loop and then terminate the program/script process when the user selects the corresponding menu option. However, in NodeJS, you cannot run a menu in a while(1) loop -- the functions called corresponding to each menu option never actually get called and the menu simply re-displays immediately.
In other words, what is the NodeJS equivalent of:
while(1) {
displayMenuToUser();
// Wait for user to select which menu option they want
if (quitMenuOptionSelectedByUser) {
terminateProcess();
} else {
executeFunctionCorrespondingToTheSelectedMenuOption();
// At this point the menu should be re-displayed so the user can select another option
}
}
You can use Inquirer.js
I made this example which keeps looping if you answer yes on the Go again? question:
var inquirer = require('inquirer');
const showMenu = () => {
inquirer
.prompt([{
name: 'age',
type: 'input',
message: 'What\'s your age?',
}, {
name: 'country',
type: 'list',
message: 'Where do you live?',
choices: ['USA', 'China', 'Germany', 'France'],
}, {
name: 'back',
type: 'input',
message: 'Go again?',
choices: ['yes', 'no'],
}]
).then((answers) => {
console.log(`\nMy age is ${answers.age} and I live in ${answers.country}.\n`);
if (answers.back === 'yes') {
return showMenu();
}
})
.catch((err) => {
console.log(err);
});
}
showMenu();

Ext.MessageBox title with font awesome icon

I was trying to set a fontawesome icon inside an Ext.MessageBox title and i managed to accomplish it using the code below:
Ext.Msg.show({
//iconCls: 'x-fa fa-times-circle',
title: '<span class="x-fa fa-exclamation"> Error Title</span>',
message: 'An error occured!!!!!',
buttons: Ext.MessageBox.OK,
width: 400
});
Reading the docs i found out that i could set the title using a config object for the Ext.panel.Title component.
But setting the config object like the example below was making the title invisible.
title: {
text: 'Error Title',
iconCls: 'x-fa fa-exclamation'
}
Also inspecting the view from the Elements tab of Chrome's Developer tools i saw that there is a div element for icons inside the x-paneltitle class.
<div class="x-icon-el x-font-icon" id="ext-element-15"></div>
How can i set the MessageBox title using the Ext.panel.Title config?
You have fallen into a documentation trap there.
The title config is available on the Ext.Panel class instantiation and therefore, technically, also on the Ext.MessageBox instantiation, but not on its show method, which you call on a singleton that has been pre-instantiated for you by Sencha.
The following would technically instantiate a Message Box with a custom title config:
Ext.create('Ext.MessageBox',{
title: {
text: 'Error Title',
iconCls: 'x-fa fa-exclamation'
}
});
However, to show the Ext.MessageBox, you have to call the show method, which has been overridden so as to overwrite every custom setting you add to the title config.
This works for me:
Ext.Msg.show({
title: {
text: 'Error Title',
iconCls: 'x-fa fa-exclamation'
},
message: 'You are closing a tab that has unsaved changes. Would you
like to save your changes?',
buttons: Ext.Msg.YESNOCANCEL,
icon: Ext.Msg.QUESTION,
fn: function(btn) {
if (btn === 'yes') {
console.log('Yes pressed');
} else if (btn === 'no') {
console.log('No pressed');
} else {
console.log('Cancel pressed');
}
}
});
Used it here:
https://docs.sencha.com/extjs/6.0.2/classic/Ext.window.MessageBox.html
It is Classic 6.0.2 but it should still work.

Open different page as defined when calling notify function in chrome extension?

In my code, I wish to be able to call the function notify each time with a different link, and the specific notification created opens a new tab with that page when clicked
Note: I'm very confused by the documentation, please don't just link me to that, I really want an explanation with an example. Thanks
This is what I have so far:
function notify(title, msg, link, callback) {
//no idea what to do with the link here
var options = {
title: title,
message: msg,
type: "basic",
iconUrl: "Icon.png"
};
return chrome.notifications.create("", options, callback);
}
And to call the function:
notify("title", "message", "http://www.example.com", function(notification) { });
which would display
Title
Message
and upon clicking, would open a new tab to http://www.example.com
then later, I would call it again with
notify("title", "message", "http://www.google.com", function(notification) { });
and that one would open a new tab to http://www.google.com when clicked
Thanks if you can help!
There is no direct support for attaching an onclick handler to a notification. Instead, if you click a notification's body, it will generate a general chrome.notification.onClicked event, providing the ID of the notification.
You will have, therefore, to maintain your own matching of IDs to URLs.
var urls = {};
chrome.notifications.onClicked.addListener(notifyClick);
chrome.notifications.onClosed.addListener(notifyClose);
function notify(title, msg, link, callback) {
var options = {
title: title,
message: msg,
type: "basic",
iconUrl: "Icon.png",
isClickable: true // New in Chrome 32, alters the appearance?
};
return chrome.notifications.create("", options, function(id) {
// New ID will be generated
urls[id] = link;
});
}
function notifyClick(id) {
// Look up the URL:
chrome.tabs.create({url: urls[id]});
// Optionally, close the notification:
// chrome.notifications.clear(id, function(){});
}
function notifyClose(id, byUser) {
// Clean up the matching
delete urls[id];
}
Please note: there is a caveat regarding closing notification programmatically. If the notification is closed from the message center, it will not immediately disappear.

Ext.MessageBox under TabPanel

I got problem like this:
There is TabPanel with two tab. First is FormPanel, second is GridPanel.
And I've added listener to beforetabchange. When values in FormPanel are changed there should appear Ext.MessageBox.cofirm with question: 'Do you want save your changes?'.
And it's appear but under TabPanel.
It doesn't work with any type of message box.
This is little bit weird because, when I click on submit button in this form, there is wait message box and after changes are saved there is information box.
Any ideas?
edited
I've removed all config sets from tabPanel and formPanel which is first tab, so everything is default. Message box looks like that (right now):
Ext.MessageBox.confirm('Title','message',Ext.emptyFn);
I think the problem is that the message box is binded somehow to gridPanel which is under the tabPanel.
I've added plugin to tabPanel and on beforetabchange event I show this confirm message.
Funny thing is that I do exactly the same code in plugin which is added to submit button in formPanel and there everything works perfect.
edited
new Ext.TabPanel({
activeTab: 0,
id: 'tabPanel_id',
items: [
new Ext.form.FormPanel({
cls: 'xf-windowForm',
bodyCssClass: '',
autoHeight: false,
autoScroll: true,
border: false,
layout: 'form',
buttonAlign: 'center',
monitorValid: true,
labelAlign: 'right',
labelPad: 10,
defaults: {
msgTarget: 'under',
anchor: '100%'
},
id: 'formPanel_id',
title: translate('tab_title-general'),
items: [
new Ext.form.TextField({
fieldLabel: 'label',
name: 'name',
id: 'id'
})
],
buttons: [
new Ext.Button({
text: 'save',
type: 'submit',
formBind: true,
plugins: {
init: function (component) {
component.on({
click: function() {
Ext.MessageBox.confirm('title', 'messsage', Ext.emptyFn);
}
});
}
}
})
]
}),
new Ext.Panel()
],
plugins: {
init: function(component) {
component.on({
beforetabchange: function() {
Ext.MessageBox.confirm('title', 'messsage', Ext.emptyFn);
}
});
}
}
});
There is also gridPanel under this tabPanel.
And this message box in buttons plugin works fine (tab panel becomes grey and message box appears on top), but the second one, in tabpanels plugin, add another mask on grid and shows under the panel and above the grid.
edited
Ext.onReady(function(){
new Ext.Window({
initHidden: false,
width: 700,
title: 'WindowTitle',
items: [
new Ext.TabPanel({
items: [
new Ext.Panel({title: 'Title1'}),
new Ext.Panel({title: 'Title2'})
],
plugins: {
init: function(component) {
component.on({
beforetabchange: function(t,c,n) {
Ext.MessageBox.confirm('MessageBoxTitle', 'Confirm message.', Ext.emptyFn, component);
}
});
}
}
})
]
});
});
That's complete code where problem occurs.
Message box in window show event is displayed ok, but in tabPanel it's under the window.
I'm working on FF 4.0.1, but problem occurs also in IE 8 and Chrome 12.
I'm using Ext JS 3.3.1.
solution
z-index of windows must be decreased (ie. to 7000, default is 9000).
To do that I'm using Ext.WindowGroup.
windows = new Ext.WindowGroup();
windows.zseed = 7000;
//and in config properties in window:
manager:windows
Thank's everyone for help.
"I think the problem is that the message box is binded somehow to gridPanel which is under the tabPanel."
MessageBox isn't bound to an existing panel, its a singleton and is basically a shortcut to creating a window rendered to the body, as per source code:
http://dev.sencha.com/deploy/ext-3.3.1/docs/source/MessageBox.html#cls-Ext.MessageBox
Kevin is on to something with the z-index being a likely culprit, as I've fixed issues in the past with the Ext.Notifications ux having a lower z-index than the main content.
Try running your messagebox call from the console and see if it appears. That will help determine if your wait messagebox is closing out the confirm messagebox (note the mention of it being a singleton above) or something odd where you're not seeing some other javascript error thats causing your code to not be run. Then, if you don't see the messagebox when run from the console, try the isVisible() api call to see if it thinks its being displayed (which will likely narrow it down to a css issue).
Ext MessageBox doesn't block your code until the user does something the way an alert() does. As a result, it's going to pop up the message box, and then proceed to render the new tab that the user just clicked on. Perhaps when the new tab renders, the Ext window manager is putting that window on top, since it rendered most recently?
You could try using setTimeout to display the message box after a short delay. That will give the new tab a chance to be on top, and then the message box renders, hopefully on top of everything, since it was the most recent.
setTimeout will work, there was same issue like
page- button -
on click - window with grid -
click on grid item->there should be a message box on top,
but it was under the window,
then i tried
click on grid item-
setTimeOut(function(){ Ext.MessageBox.alert('MessageBoxTitle', 'Confirm message.')}, 200);
I have used following method. It is working for me.
beforetabchange: function(tabpanel, newTab, oldTab){
if (!tabpanel.allowAction){
Ext.Msg.confirm('Confirm', 'Your Message',function(btn) {
if (btn == 'yes') {
/* logic*/
tabpanel.allowAction = true;
this.setActiveTab(newTab.id);
}else{ /* logic */}
});
return false;
}
delete tabpanel.allowAction;
}
Ext.create('Ext.window.MessageBox', {
alwaysOnTop: true,
closeAction: 'destroy'
}).show({
title: 'Title',
buttons: Ext.Msg.OK,
message: 'Message'
});
This should make the MessageBox appear on top.
Look at the fourth example in this page.
http://docs.sencha.com/extjs/5.1.0/api/Ext.window.MessageBox.html

Categories

Resources