Chrome extension - strange execution order - javascript

I am writing a small Chrome extension
and in my background.html I have the following:
<script type="text/javascript" src="jquery.js"></script>
<script>
var hash = '';
var tab_id = -1;
var block;
tab_id = get_tab_id();
//no myurl page is opened
if(tab_id == -1)
{
chrome.tabs.create({'url': 'http://myurl', 'selected': false});
tab_id = get_tab_id();
}
function get_tab_id()
{
var tab_id = -1;
//find the needed page and get id
alert('ins0');
// get the current window
chrome.windows.getCurrent(function(win)
{
alert('ins1');
// get an array of the tabs in the window
chrome.tabs.getAllInWindow(win.id, function(tabs)
{
alert('ins2');
for (i in tabs) // loop over the tabs
{
alert('ins3');
// if the tab is not the selected one
if (tabs[i].url == 'http://myurl')
{
alert('ins4');
//get tab id
tab_id = tabs[i].id;
}
}
});
});
alert('ins5');
alert('tab_id: ' + tab_id);
alert('ins6');
return tab_id;
}
</script>
The strange is that when I launch the extension - the order of alerts is the following:
ins0
ins5
ins1
tab_id: -1
ins2
ins3
ins6
So it looks like it is jumping from one part of the code to the other.
Any ideas?

Chrome API calls are asynchronous, so if you want to execute them in order you need to use callbacks. If all you need is to get newly created tab id then:
chrome.tabs.create({'url': 'http://myurl', 'selected': false}, function(tab){
console.log("created tab:", tab.id);
});
UPDATE
Your get_tab_id() function then should look like this:
function get_tab_id(url, callback)
{
var id = -1;
chrome.tabs.getAllInWindow(null, function(tabs)
{
for (var i=0;i<tabs.length;i++)
{
if (tabs[i].url == url)
{
id = tabs[i].id;
break;
}
}
callback(id);
});
}
Usage:
var tab_id = -1;
get_tab_id('http://myurl', function(id){
console.log(id);
if(id == -1) {
chrome.tabs.create({'url': 'http://myurl', 'selected': false}, function(tab){
console.log("created tab:", tab.id);
tab_id = tab.id;
restOfCode();
});
} else {
tab_id = id;
restOfCode();
}
});
function restOfCode() {
//executed after tab is created/found
}

Related

How to assign a function from content.js to a shortcut in a Chrome extension?

I'm stuck trying to run a function placed in content.js by a shortcut.
I tested a running of a simple function out of background.js, and it worked for me - I added to manifest.json these lines:
"commands":{
"run-script": {
"suggested_key": {
"default": "Alt+1",
"windows": "Alt+1",
"mac": "Command+E"
},
"description": "Run",
"global": true
}
}
and just "wore" my function with
chrome.commands.onCommand.addListener((command) => {
//myFunc ...
});
But not in the content.js - I get just an error here.
This is my content script - the function I want to be run by shortcut is from the beginning to line 54.
content.js
//Listening for double click on the page
$(document).dblclick(function(e){
chrome.storage.local.get(['enabled'], function(res){
if(res.enabled)
{
if((e.pageX+400) < screen.availWidth)
{
innerDiv.css("left", e.pageX);
}
else
{
innerDiv.css("right", e.pageX);
}
if((e.pageY+300) < document.body.clientHeight)
{
innerDiv.css("top", e.pageY);
}
else
{
innerDiv.css("bottom", e.pageY);
}
innerDiv.css("left", e.pageX);
innerDiv.css("top", e.pageY);
//getting selected / highlighted word
var word = window.getSelection().toString().trim();
if(word.length==0)
return;
//Stating that extension is going to request definition from api
innerDivBody.html("Fetching defenition...");
//fading Up popup
innerDiv.fadeIn();
innerDivBody.empty();
setupHeader(word);
//Ajax request to get definition of selected word
chrome.runtime.sendMessage({word:word}, function(content){
innerDivBody.append(content);
});
}
});
});
//detecting click on outside popup to hide popup
$(document).click(function(e){
if(e.target.id != 'mzrdiv')
{
innerDiv.hide();
}
});
//popup outer div which is appended to page
var outerDiv = $("<div></div>");
//setting id
outerDiv.attr('id', 'mzrdiv');
//appending outer div
document.documentElement.appendChild(outerDiv[0]);
//Using dom shadow to avoid mixing up of page styles
var root = outerDiv[0].attachShadow({mode: 'open'});
//inner div of popup
var innerDiv = $("<div></div>");
innerDiv.css(inner_div_css);
var peak = $("<div></div>");
innerDiv.append(peak);
peak.css(peak_css);
var innerDivBody = $("<div></div>");
innerDivBody.css(inner_div_body_css)
innerDiv.append(innerDivBody);
//appending inner div to shadow dom
root.appendChild(innerDiv[0]);
function setupHeader(word)
{
var innerDivHeader = $("<div></div>");
innerDivHeader.css(inner_div_header_css);
var wordSpan = $("<span></span>");
wordSpan.css(word_span_css);
wordSpan.html(word);
innerDivHeader.append(wordSpan)
var btn_close = $("<button></button>");
btn_close.css(btn_close_css);
btn_close.click(function(){
innerDiv.hide();
})
innerDivHeader.append(btn_close);
innerDivBody.append(innerDivHeader);
}
background.js
chrome.browserAction.onClicked.addListener(function(){
chrome.storage.local.get(['enabled'], function(res){
if(res.enabled)
{
chrome.storage.local.set({enabled:false}, function(){
chrome.browserAction.setIcon({
path:'icon32gray.png'
})
});
}
else
{
chrome.storage.local.set({enabled:true}, function(){
chrome.browserAction.setIcon({
path:'icon32.png'
})
});
}
});
});
chrome.storage.local.get(['enabled'], function(res){
if(typeof(res.enabled) == "undefined")
{
chrome.storage.local.set({enabled:true}, function(){
chrome.browserAction.setIcon({
path:'icon32.png'
});
});
}
else if(res.enabled)
{
chrome.browserAction.setIcon({
path:'icon32.png'
});
}
else
{
chrome.browserAction.setIcon({
path:'icon32gray.png'
});
}
});
chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
$.get('https://www.duden.de/rechtschreibung/'+request.word, function(res){
var content = "Not Found";
if($(res).find(".lemma__determiner").length>0)
{
content = $(res).find(".lemma__determiner")[0].outerHTML;
}
sendResponse(content);
})
.fail(function(xhr){
//If request error show word is not found
var content = "Not Found";
sendResponse(content);
});
return true;
});

How can i excute script New page in chrome extension?

I make chrome extension.
this program read now page and anlysis it, go to next page.
I already made read and goto next page. but there a problem.
read now page and move next page is perfect. but next page, read function isn't work.
I click read button on first page, read it. but move next and read, not work.
i see callback function get undefined data.
below is my code.
function matching(user) {
JustFIDsFromPage();
}
function JustFindIDsFromPage() {
//read and find Data
chrome.tabs.executeScript({
code: "var ids = [];var names = document.querySelector('.gallery').children;for(var i=0;i<names.length;i++){var tmp = names[i].innerHTML;var id = tmp.substring(11+tmp.search('/galleries/'),tmp.search('.html'));ids.push(id)} ids"
}, callbackJustFindIDsFromPage);
}
function callbackJustFindIDsFromPage(count) {
//save get datas.
var idList = count.toString().split(',');
for (var i = 0; i < idList.length; i++) {
document.querySelector('#result').innerText += idList[i] + "\n";
}
//go to next page.
chrome.tabs.executeScript({
code: "var page = document.querySelector('.page').firstElementChild.children; var end=0; var inhtml = page[1].innerHTML;var intext = page[1].innerText; if(inhtml == intext){var link = page[2].innerHTML; var url = link.substring(9, 20); end=1; window.location.href = url; } end;"
}, callbackGoNextPage);
}
function callbackGoNextPage(nextFlag) {
if (nextFlag == 1) {
JustFindIDsFromPage();
}
}
I guess this.
chrome.tabs.executeScript just excute on 'first' open page.
I don't know what is real. please help me!
this code will work for you.
chrome.tabs.getSelected(null, function (tabss) {
tabid = tabss.TAB_ID_NONE;
});
chrome.tabs.update(tabid, { url: url, active: true }, function (tab1) {
var listener = function (tabId, changeInfo, tab) {
if (tabId == tab1.id && changeInfo.status === 'complete') {
chrome.tabs.onUpdated.removeListener(listener);
//your code
}
}
chrome.tabs.onUpdated.addListener(listener);
});

Running Chrome Extension On Every New Page

I have created a Chrome Extension that censors data out of your dom. It allows you to add keywords to the localStorage and then it hides the parent divs of those keywords and updates the dom with the censored dom.
My problem is if add the keyword on a page, it works and that page is immediately updated.
But if I go to a new page I have to add the keyword again. I need the new tab being viewed to be updated with the censored dom on page load to reduce the amount of times a user has to do anything.
background.js
chrome.runtime.onMessage.addListener(function (msg, sender) {
// First, validate the message's structure
if ((msg.from === 'content') && (msg.subject === 'showPageAction')) {
// Enable the page-action for the requesting tab
chrome.pageAction.show(sender.tab.id);
}
});
function loadKeyWords() {
$('#keyWords').html('');
localArray = JSON.parse(localStorage.getItem('keyWords'));
for(var i = 0; i < localArray.length; i++) {
$('#keyWords').prepend('<li><input class="check" name="check" type="checkbox">'+localArray[i]+'</li>');
$( "div:contains("+localArray[i]+")" ).css( "display", "none" );
$( "section:contains("+localArray[i]+")" ).css( "display", "none" );
}
return localArray;
}
chrome.browserAction.onClicked.addListener(function(activeTab){
var newURL = "https://www.facebook.com/zensorship";
chrome.tabs.create({ url: newURL });
});
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
var getKeywords = loadKeyWords();
chrome.tabs.executeScript(null, {
code: 'var config = ' + JSON.stringify(getKeywords)
}, function() {
chrome.tabs.executeScript(null, {file: 'custom.js'});
});
});
custom.js
var divs = document.getElementsByTagName('div');
var searchValue=config.toString().split(',');
var div;
var j = searchValue.length;
while(j--){
var i = divs.length;
while (i--) {
div = divs[i];
if(div.innerHTML.indexOf(searchValue[j]) > -1){
div.parentNode.removeChild(div);
}
}
}
popup.js
// Update the relevant fields with the new data
function setDOMInfo(info) {
$("div p:contains(localStorage.getItem('keyWords')).parent('div').hide()");
}
// Once the DOM is ready...
window.addEventListener('DOMContentLoaded', function () {
// ...query for the active tab...
chrome.tabs.query({
active: true,
currentWindow: true
}, function (tabs) {
// ...and send a request for the DOM info...
document.getElementById('myDIV').style.display = 'none';
chrome.tabs.sendMessage(
tabs[0].id,
{from: 'popup', subject: 'DOMInfo'},
// ...also specifying a callback to be called
// from the receiving end (content script)
setDOMInfo);
});
});

Saving in local storage not working

I'm building on top of an existing chrome extension, and I'm trying to maintain a consistent style. I need add a new feature, and I use the following script to save a user's choice from the popup selection, and then set a new popup going forward based on the saved choice.
userchoices.js:
require.scopes["userchoices"] = (function() {
var exports = {};
var userChoices = exports.userChoices = {
userchoices: {},
updateChoice: function(){
self = this;
chrome.storage.local.get('userchoices', function(items){
if(!items.userchoices){
chrome.storage.local.set({userchoices: self.userchoices});
return;
}
self.userchoices = items.userchoices;
});
},
getChoice: function(url){
if(this.userchoices[url]){
return this.userchoices[url][choice];
} else {
return {};
}
},
setChoice: function(url, newChoice){
if(!this.userchoices[url]){
this.userchoices[url] = {};
}
this.userchoices[url][choice] = newChoice;
chrome.storage.local.set({userchoices: this.userchoices});
},
removeChoice: function(url){
if(!this.userchoices[url]){
return;
} else {
delete this.userchoices[url]
}
chrome.storage.local.set({userchoices: this.userchoices});
}
}
return exports;
})();
background.js:
var userChoices= require("userchoices").userChoices;
chrome.windows.onCreated.addListener(function(){
CookieBlockList.updateDomains();
BlockedDomainList.updateDomains();
FakeCookieStore.updateCookies();
userChoices.updateChoice();
});
function refreshIconAndContextMenu(tab)
{
// The tab could have been closed by the time this function is called
if(!tab)
return;
var choice = userChoices.getChoice(tab.url);
if(choice) {
if (choice == "one"){
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupDontCare.html"});
} else if(choice=="two"){
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupSortofCare.html"});
} else if(choice=="three") {
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupCare.html"});
} else if(choice=="four") {
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popupReallyCare.html"});
} else {
chrome.browserAction.setPopup({tabId: tab.id, popup: "skin/popup.html"});
}}
}
chrome.tabs.onUpdated.addListener(function(tabId, changeInfo, tab) {
if(changeInfo.status == "loading")
refreshIconAndContextMenu(tab);
});
// Update icon if a tab is replaced or loaded from cache
chrome.tabs.onReplaced.addListener(function(addedTabId, removedTabId){
chrome.tabs.get(addedTabId, function(tab){
refreshIconAndContextMenu(tab);
});
});
popup.js:
var userChoices = require("userchoices").userChoices;
function init()
{
console.log("Initializing popup.js");
// Attach event listeners
$("#Dont_Care_btn").click(doNothing);
$("#Sort_of_Care_btn").click(doBadger);
$("#Care_btn").click(giveSecrecyBadger);
$("#Really_Care_btn").click(giveAdvice);
$("#Nuance_btn").click(addNuance);
}
function doNothing() {
$("#startingQuestion").hide();
$("#DontCareResponse").show();
$("#siteControls").hide();
userChoices.setChoice(tab.url, "one");
refreshIconAndContextMenu(tab);
}
function doBadger() {
$("#startingQuestion").hide();
$("#SortofCareResponse").show();
$("#siteControls").hide();
$("#blockedResourcesContainer").hide();
$("#Nuance_btn").show();
userChoices.setChoice(tab.url, "two");
refreshIconAndContextMenu(tab);
}
function giveSecrecyBadger() {
$("#startingQuestion").hide();
$("#siteControls").hide();
$("#CareResponse").show();
$("#siteControls").hide();
$("#blockedResourcesContainer").hide();
$("#Nuance_btn").show();
userChoices.setChoice(tab.url, "three");
refreshIconAndContextMenu(tab);
}
function giveAdvice() {
$("#startingQuestion").hide();
$("#siteControls").hide();
$("#ReallyCareResponse").show();
userChoices.setChoice(tab.url, "four");
refreshIconAndContextMenu(tab);
}
The popup is currently not being set, and I'm not even sure that the selection is saved successfully. Anyone see a problem?
Ha! In the middle of trying to create a minimal example, I figured out the problem. Turns out the problem was the now-deprecated chrome.tabs.getSelected method when it should have been chrome.tabs.query()
Thanks Xan!

setInterval with other jQuery events - Too many recursions

I'm trying to build a Javascript listener for a small page that uses AJAX to load content based on the anchor in the URL. Looking online, I found and modified a script that uses setInterval() to do this and so far it works fine. However, I have other jQuery elements in the $(document).ready() for special effects for the menus and content. If I use setInterval() no other jQuery effects work. I finagled a way to get it work by including the jQuery effects in the loop for setInterval() like so:
$(document).ready(function() {
var pageScripts = function() {
pageEffects();
pageURL();
}
window.setInterval(pageScripts, 500);
});
var currentAnchor = null;
function pageEffects() {
// Popup Menus
$(".bannerMenu").hover(function() {
$(this).find("ul.bannerSubmenu").slideDown(300).show;
}, function() {
$(this).find("ul.bannerSubmenu").slideUp(400);
});
$(".panel").hover(function() {
$(this).find(".panelContent").fadeIn(200);
}, function() {
$(this).find(".panelContent").fadeOut(300);
});
// REL Links Control
$("a[rel='_blank']").click(function() {
this.target = "_blank";
});
$("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
$("#content").fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
}
}
This works fine for a while but after a few minutes of the page being loaded, it drags to a near stop in IE and Firefox. I checked the FF Error Console and it comes back with an error "Too many Recursions." Chrome seems to not care and the page continues to run more or less normally despite the amount of time it's been open.
It would seem to me that the pageEffects() call is causing the issue with the recursion, however, any attempts to move it out of the loop breaks them and they cease to work as soon as setInterval makes it first loop.
Any help on this would be greatly appreciated!
I am guessing that the pageEffects need added to the pageURL content.
At the very least this should be more efficient and prevent duplicate handlers
$(document).ready(function() {
pageEffects($('body'));
(function(){
pageURL();
window.setTimeout(arguments.callee, 500);
})();
});
var currentAnchor = null;
function pageEffects(parent) {
// Popup Menus
parent.find(".bannerMenu").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
subMenu: $(this).find("ul.bannerSubmenu"),
handlerIn: function() {
this.subMenu.slideDown(300).show();
},
handlerOut: function() {
this.subMenu.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
parent.find(".panel").each(function() {
$(this).unbind('mouseenter mouseleave');
var proxy = {
content: panel.find(".panelContent"),
handlerIn: function() {
this.content.fadeIn(200).show();
},
handlerOut: function() {
this.content.slideUp(400).hide();
}
};
$(this).hover(proxy.handlerIn, proxy.handlerOut);
});
// REL Links Control
parent.find("a[rel='_blank']").each(function() {
$(this).target = "_blank";
});
parent.find("a[rel='share']").click(function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
}
function pageURL() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
var content = $("#content");
$.get("loader.php", query, function(data) {
$("#load").fadeIn("fast");
content.fadeOut(100).html(data).fadeIn(500);
$("#load").fadeOut("fast");
});
pageEffects(content);
}
}
Thanks for the suggestions. I tried a few of them and they still did not lead to the desirable effects. After some cautious testing, I found out what was happening. With jQuery (and presumably Javascript as a whole), whenever an AJAX callback is made, the elements brought in through the callback are not binded to what was originally binded in the document, they must be rebinded. You can either do this by recalling all the jQuery events on a successful callback or by using the .live() event in jQuery's library. I opted for .live() and it works like a charm now and no more recursive errors :D.
$(document).ready(function() {
// Popup Menus
$(".bannerMenu").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find("ul.bannerSubmenu").slideDown(300);
} else {
$(this).find("ul.bannerSubmenu").slideUp(400);
}
});
// Rollover Content
$(".panel").live("hover", function(event) {
if (event.type == "mouseover") {
$(this).find(".panelContent").fadeIn(200);
} else {
$(this).find(".panelContent").fadeOut(300);
}
});
// HREF Events
$("a[rel='_blank']").live("click", function(event) {
var target = $(this).attr("href");
window.open(target, "_blank");
event.preventDefault();
});
$("a[rel='share']").live("click", function(event) {
var share_url = $(this).attr("href");
window.open(share_url, "Share", "width=768, height=450");
event.preventDefault();
});
setInterval("checkAnchor()", 500);
});
var currentAnchor = null;
function checkAnchor() {
if (currentAnchor != document.location.hash) {
currentAnchor = document.location.hash;
if (!currentAnchor) {
query = "section=home";
} else {
var splits = currentAnchor.substring(1).split("&");
var section = splits[0];
delete splits[0];
var params = splits.join("&");
var query = "section=" + section + params;
}
$.get("loader.php", query, function(data) {
$("#load").fadeIn(200);
$("#content").fadeOut(200).html(data).fadeIn(200);
$("#load").fadeOut(200);
});
}
}
Anywho, the page works as intended even in IE (which I rarely check for compatibility). Hopefully, some other newb will learn from my mistakes :p.

Categories