Trying to create a simple addon to retry a duckduckgo search in google. It parses the current duckduckgo url search params, appends them to a google url, and opens that url in a new tab.
The searchGoogle.js works great when pasted directly into the console context of a duckduckgo search. And the addon loads correctly in about:debugging... But I am unable to get the "searchGoogle.js" to fire on button (browser_action) click. What am I missing here?
manifest.json
{
"manifest_version": 2,
"name": "SearchGoogle",
"version": "1.0",
"description": "Repeats a duckduckgo search in a new tab using google.",
"icons": {
"48": "icons/48search-pointer-icon.png",
"32": "icons/32search-pointer-icon.png",
"16": "icons/16search-pointer-icon.png"
},
"permissions": [
"tabs",
"activeTab",
"webRequest",
"webNavigation"
],
"browser_action": {
"default_icon": "icons/48search-pointer-icon.png",
"default_title": "SearchGoogle"
},
"background": {
"scripts": ["searchGoogle.js"]
}
}
searchGoogle.js
var myStr = window.location.href;
var googurl = 'https://www.google.com/search?q=';
var params = getmyuri('q', myStr);
window.open(googurl+params, '_blank');
window.focus();
window.alert(googurl+params);
function getmyuri(n,s){
n = n.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");
var p = (new RegExp("[\\?&]"+n+"=([^&#]*)")).exec(s);
return (p===null) ? "" : p[1];
}
What you're currently doing is merely declaring a background script. A background script is loaded when the addon is loaded by the browser, but you need some code to react to other events.
Here's what I found in the MDN pages of browser_action :
If you don't supply a popup, then a click event is dispatched to your extension's background scripts when the user clicks the button.
(...)
The extension's background scripts can receive click events when the user clicks the icon using code like this:
browser.browserAction.onClicked.addListener(function(){})
So in your case, you need to wrap your "on click" code into this browserAction.onClicked event handler, something like this:
// searchGoogle.js
browser.browserAction.onClicked.addListener(function(){
var myStr = window.location.href;
var googurl = 'https://www.google.com/search?q=';
var params = getmyuri('q', myStr);
window.open(googurl+params, '_blank');
window.focus();
window.alert(googurl+params);
});
And voilà, your code should be executed everytime you click the browserAction icon.
For anyone else who comes here with the same question. Here are lessons observed:
window.alert is not a thing in a background script. Instead, wrap things in console.log(). Logging to console from Firefox extension?
Event listeners can pass tab information already, see tabs.getCurrent() result is undefined?.
To fire on button click, DON'T supply a popup in the manifest, and DO wrap the code to be fired in browser.browserAction.onClicked.addListener(function(){}).
Here's the final working script.
Main stays the same.
JS is:
browser.browserAction.onClicked.addListener(function(tab){
function getmyuri(n,s){
n = n.replace(/[\[]/,"\\[").replace(/[\]]/,"\\]");
var p = (new RegExp("[\\?&]"+n+"=([^&#]*)")).exec(s);
return (p===null) ? "" : p[1];
}
console.log(tab)
var googurl = 'https://www.google.com/search?q=';
var params = getmyuri('q', tab.url);
browser.tabs.create({url: googurl+params});
});
Related
Following these instructions, I went to about:debugging -> This Firefox and clicked Inspect on my extension, which shows a console. But no logs show up there when I trigger my extension. Using the list-cookies example, I added the last two lines:
gettingAllCookies.then((cookies) => {
//set the header of the panel
var activeTabUrl = document.getElementById('header-title');
var text = document.createTextNode("Cookies at: "+tab.title);
var cookieList = document.getElementById('cookie-list');
console.log('I can't see this log!');
cookieList.parentNode.appendChild(document.createTextNode(Date()));
When I invoke the popup, I see the current date/time in the popup, but no log shows up in the console.
I tried setting extensions.sdk.console.logLevel and restarting as mentioned here (even though I think that's for older versions), but it didn't help.
I thought maybe there's a console permission or something I might need to add to the manifest, but didn't find any such thing.
Complete code for reference. I only changed the lines marked with +/-:
function showCookiesForTab(tabs) {
//get the first tab object in the array
let tab = tabs.pop();
//get all cookies in the domain
var gettingAllCookies = browser.cookies.getAll({url: tab.url});
gettingAllCookies.then((cookies) => {
//set the header of the panel
var activeTabUrl = document.getElementById('header-title');
var text = document.createTextNode("Cookies at: "+tab.title);
var cookieList = document.getElementById('cookie-list');
- activeTabUrl.appendChild(text);
+
+ console.log('I can't see this log!');
+ cookieList.parentNode.appendChild(document.createTextNode(Date())); // I see this updated even though I don't see the log
if (cookies.length > 0) {
//add an <li> item with the name and value of the cookie to the list
for (let cookie of cookies) {
let li = document.createElement("li");
let content = document.createTextNode(cookie.name + ": "+ cookie.value);
li.appendChild(content);
cookieList.appendChild(li);
}
} else {
let p = document.createElement("p");
let content = document.createTextNode("No cookies in this tab.");
let parent = cookieList.parentNode;
p.appendChild(content);
parent.appendChild(p);
}
});
}
//get active tab to run an callback function.
//it sends to our callback an array of tab objects
function getActiveTab() {
return browser.tabs.query({currentWindow: true, active: true});
}
getActiveTab().then(showCookiesForTab);
Firefox console has been divided into different areas. The result of console.log() can be viewed in the relative area.
Multiprocess Browser Console Ctrl+Shift+J
Mostly logs by Firefox itself
Web Developer Tools Ctrl+Shift+I or F12
Logs by Tab/Webpage and Content scripts of addons
Extension Toolbox about:debugging#/runtime/this-firefox ➜ XYZaddon ➜ Inspect
Logs by background scripts of XYZaddon
Update
Based on comments, here is a tested simplified code that you can work on. The log shows on Extension Toolbox.
async function showCookiesForTab() {
// get the first tab object in the array
const tabs = await browser.tabs.query({currentWindow: true, active: true});
// get all cookies in the domain
const cookies = await browser.cookies.getAll({url: tabs[0].url});
console.log(cookies);
// Array(6) [ {…}, {…}, {…}, {…}, {…}, {…} ]
}
showCookiesForTab();
I had a similar issue. I didn’t figure out the cause, but I find a way to see the console.log in the Extension Toolbox.
I added a background script to handle most of the popup.js logic.
And since there is a background script running, I can see the log.
Still don’t why I couldn’t see the log in the first place.
I've managed to create a simple interactive button Slack app using a Google Apps Script (GAS).
I know how to replace the original message w/ the response, but I would like to replace only the buttons, as demonstrated (but not clearly explained) multiple places in the Slack Interactive Button documentation:
https://api.slack.com/docs/message-buttons#crafting_your_message
I'd like to do what's demonstrated here:
https://a.slack-edge.com/dcb1/img/api/message_guidelines/Example_6.gif
Is this an update of the original message, a replacement of the original message with identical text but different attachment, ...?
My current interactive buttons message code looks like this:
function sendMsgWithButton() {
// slack channel url (where to send the message)
var slackUrl = "https://hooks.slack.com/services/...";
// message text
var messageData = {
"text": "Here's your interactive buttons message.",
"attachments": [
{
"text": "Can you click the button?",
"fallback": "Sorry, no support for buttons.",
"callback_id": "ptNotificationButtonResponse",
"color": "#3AA3E3",
"attachment_type": "default",
"actions": [
{
"name": "userResponse",
"text": "OK",
"style": "primary",
"type": "button",
"value": "ok"
}
]
}
]
}
// format for Slack
var options = {
'method' : 'post',
'contentType': 'application/json',
// Convert the JavaScript object to a JSON string.
'payload' : JSON.stringify(messageData)
};
// post to Slack
UrlFetchApp.fetch(slackUrl, options);
}
My current action URL code right now looks like this:
function doPost() {
var replyMessage = {"replace_original": true,
"response_type": "in_channel",
"text": "I see you clicked the button."
};
return ContentService.createTextOutput(JSON.stringify(replyMessage)).setMimeType(ContentService.MimeType.JSON);
}
Instead of replacing the entire original message, I'd like to replace just the buttons with something like a checkbox and confirmation message as demonstrated in the gif above.
Thanks!
You can only replace the complete message, not just a part.
There are two options to update the original message:
Respond to the Slack request with {"replace_original": true}
Use chat.update
If your original message was not of type ephemeral you will get a copy of the original message as part of the payload from Slack in the original_message property, which can be helpful to update the exchange the original message.
See this page in the Slack documentation as reference.
I recently started learning firefox addon development using Addon-SDK.
I created a simple addon which displays the current webpages URL, but I'm not getting the results.
Here's my main.js file
var widgets = require("sdk/widget");
var tabs = require("sdk/tabs");
var data = require("sdk/self").data;
var showipWidget = widgets.Widget({
id : "show-ip",
label : "Display IP Address of current Page",
contentURL : data.url("lens_icon.png"),
contentScriptURL : data.url("click_handler.js"),
/*onClick : function() {
var curtab = tabs.activeTab;
console.log(curtab.url+" is Opened in Browser.");
}*/
});
And The ContentScript click_handler.js
document.write(document.URL);
However when I use onClick event (commented code above) the URL is logged in console.
I think I'm accessing document object in wrong way. Can anyone show me how to do it right way.
That's weird that should work.
But try putting this in your content script:
var check = self.port.on("check", function() {
var location = window.location.href;
alert(location + " is opened in browser");
}
then emit that check function.
Figured out my problem. It was a silly mistake, I used contentScriptURL which is wrong. The correct term is contentScriptFile. I mixed content and contentURL with contentScript.
Reference from firefox:
http://tinypic.com/r/34447mc/8
I work on a Windows 8 app, and from a page that I use link hystory for running back and forward through the app, I also have 3 or 4 links to external websites(eg: facebook or my site). I tried to run them in iframe, or also to make them open in the default browser like simple links. Both method resulted in an error in base.js that says it can't handle my error (!?) I searched a lot before asking here. I watched msdn sample that works just fine, but if i copy what I need in my app results in the same error. I I use it from another page where I dont have forward history, it works, but i really need it on the front page. Any ideeas? Thank you very much.
LE:
This is my items.js code: ( for the items.html page )
(function () {
"use strict";
var appViewState = Windows.UI.ViewManagement.ApplicationViewState;
var ui = WinJS.UI;
ui.Pages.define("/pages/items/items.html", {
// This function is called whenever a user navigates to this page. It
// populates the page elements with the app's data.
ready: function (element, options) {
var listView = element.querySelector(".itemslist").winControl;
listView.itemDataSource = Data.groups.dataSource;
listView.itemTemplate = element.querySelector(".itemtemplate");
listView.oniteminvoked = this._itemInvoked.bind(this);
this._initializeLayout(listView, Windows.UI.ViewManagement.ApplicationView.value);
listView.element.focus();
WinJS.Utilities.query("a").listen("click", this.linkClickEventHandler, false);
},
// This function updates the page layout in response to viewState changes.
updateLayout: function (element, viewState, lastViewState) {
/// <param name="element" domElement="true" />
var listView = element.querySelector(".itemslist").winControl;
if (lastViewState !== viewState) {
if (lastViewState === appViewState.snapped || viewState === appViewState.snapped) {
var handler = function (e) {
listView.removeEventListener("contentanimating", handler, false);
e.preventDefault();
}
listView.addEventListener("contentanimating", handler, false);
var firstVisible = listView.indexOfFirstVisible;
this._initializeLayout(listView, viewState);
if (firstVisible >= 0 && listView.itemDataSource.list.length > 0) {
listView.indexOfFirstVisible = firstVisible;
}
}
}
},
linkClickEventHandler: function (eventInfo) {
eventInfo.preventDefault();
var link = eventInfo.target;
WinJS.Navigation.navigate(link.href);
},
// This function updates the ListView with new layouts
_initializeLayout: function (listView, viewState) {
/// <param name="listView" value="WinJS.UI.ListView.prototype" />
if (viewState === appViewState.snapped) {
listView.layout = new ui.ListLayout();
} else {
listView.layout = new ui.GridLayout();
}
},
_itemInvoked: function (args) {
var groupKey = Data.groups.getAt(args.detail.itemIndex).key;
WinJS.Navigation.navigate("/pages/split/split.html", { groupKey: groupKey });
}
});
})();
And from items.html I have different types of links: some of them links to other application pages, from where I can return with history buttons back/forward and some of them are links to external page. Simple link.These links crashes my app with the error that I mentioned below. If I erase the next line:
WinJS.Utilities.query("a").listen("click", this.linkClickEventHandler, false);
from my js script, external links works, but I dont have anymore history buttons in my others's app pages.
You are trying to use the navigation framework to navigate to an external URI. It's usually meant to be used within the application's local context and pages that can contain 'fragments' to load up into your main nav control.
I wouldn't hook anchor tags with your function call, instead in your linkClickEventHandler I would do the following to only hook your internal links
WinJS.Utilities.query(".nav").listen("click", linkClickEventHandler, false);
in turn your internal links would be
click me
This approach only hooks the navigation framework into your internal links. Another approach is to inspect the 'this.href' in your handler and if it contains http:// or https:// then call window.open instead
I would like to save the HTML document in the current tab using a Firefox Add-on created with the Add-on SDK.
I'm trying like this:
exports.main = function() {
require("widget").Widget({
id: "foo",
label: "My Test",
contentURL: "http://www.mozilla.org/favicon.ico",
onClick: function(event) {
var {Cc, Ci} = require("chrome");
var persist = Cc["#mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Ci.nsIWebBrowserPersist);
var localPath = Cc["#mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
localPath.initWithPath("/tmp/");
var localFile = localPath.clone();
localFile.append("mylocalfile.html");
var tabs = require("tabs");
persist.saveDocument(tabs.activeTab, localFile, localPath, null, 0, 0);
}
});
};
But the code above crashes Firefox (15.0) when I click on the widget.
I guess that tabs.activeTab might not be a nsIDOMDocument? Is that the problem?
How should I do to make it work?
tabs.activeTab is definitely not an nsIDOMDocument, please see the docs here:
https://addons.mozilla.org/en-US/developers/docs/sdk/latest/packages/addon-kit/tabs.html
You should instead be able to simply open a tab via tabs.open, and attach content scripts to the opened tab. Here is an example of how to attach content scripts to an opened tab:
https://builder.addons.mozilla.org/package/22176/latest/