I am writing a chrome extension which should change the content-type of http responses. It is working fine. Now, I want to control it using keypress i.e. user should be able to bypass the default action of extension on keypress. I tried this, but it doesn't work:
background.js
var enableEXT = true;
window.onkeydown = function()
{
console.log('Testing hello');
if (event.keyCode == 70)
enableEXT = false;
console.log(event.keyCode);
console.log(enableEXT);
};
window.onkeyup = function()
{
enableEXT = true;
console.log(event.keyCode);
};
chrome.webRequest.onHeadersReceived.addListener(function(details) {
for (var i = 0; i < details.responseHeaders.length; ++i)
{
if (details.responseHeaders[i].name.toLowerCase() == 'content-type' && !enableEXT)
details.responseHeaders[i].value = 'application/xyz';
}
return {responseHeaders: details.responseHeaders};
}, {urls: ["<all_urls>"]}, ['blocking', 'responseHeaders']);
Try using a content script, injected into the web page, instead of a background script. Use this in your manifest.json:
"content_scripts" : [{
"js" : ["myScript.js"]
}]
"permissions": [
"tabs", "http://*/*", "https://*/*"
]
However, chrome extensions are sandboxed from other scripts in the page. However, you do have access to the DOM and you can inject your own tags. So, create a new <script> tag and append it to the DOM, and the new script (script.js) it references can include the event listeners you want.
background.js:
chrome.runtime.onConnect.addListener(function(port) {
port.onMessage.addListener(function(msg) {
enableEXT = msg.enableEXT;
});
});
chrome.webRequest.onHeadersReceived.addListener(function(details) {
for (var i = 0; i < details.responseHeaders.length; ++i)
{
if (details.responseHeaders[i].name.toLowerCase() == 'content-type' && !enableEXT)
details.responseHeaders[i].value = 'application/xyz';
}
return {responseHeaders: details.responseHeaders};
}, {urls: ["<all_urls>"]}, ['blocking', 'responseHeaders']);
myScript.js:
//to inject into the page
var s = document.createElement('script');
s.src = chrome.extension.getURL("script.js");
s.onload = function() {
this.parentNode.removeChild(this);
};
(document.head||document.documentElement).appendChild(s);
//to communicate with our background
var port = chrome.runtime.connect();
window.addEventListener("message", function(event) {
// We only accept messages from ourselves
if (event.source != window)
return;
if (event.data.type && (event.data.type == "FROM_PAGE")) {
port.postMessage(event.data);
}
}, false);
script.js:
window.onkeydown = function()
{
if (event.keyCode == 70)
window.postMessage({ enableEXT: true, "*");
};
window.onkeyup = function()
{
window.postMessage({ enableEXT: false, "*");
};
To communicate between your injected code, your content script, and your background page is a very awkward situation, but can be dealt with, with all the postMessage APIs...
Add a parameter named event to the event handlers you assign to the events like this:
window.onkeydown = function(event)
{
console.log(event.keyCode);
};
Related
I have a script inside a child google tag manager account which is firing on submission of an iframe form that is generated via javascript, this should be picked up via the parent google tag manager account through the dataLayer. I am following this tutorial: https://measureschool.com/iframe-tracking/
However it's not going into the dataLayer on the parent - hence the tag isn't firing. Can anyone help?
To confirm
Child tag manager account fires at: https://new.bokuntest.com/ - the iframe form URL
Parent tag manager account fires at: https://bokun.io/
URL of page with embedded iframe form: https://bokun.io/copy-of-free-trial
postMessage tag firing in child:
<script>
try {
var postObject = JSON.stringify({
event: 'iframeFormSubmit',
form: 'Registration'
});
parent.postMessage(postObject, 'https://new.bokuntest.com');
} catch(e) {
window.console && window.console.log(e);
}
</script>
Listener tag on parent (trigger = fire on all pages):
<script type="text/javascript">
(function(window) {
addEvent(window, 'message', function(message) {
try{
var data = JSON.parse(message.data);
var dataLayer = window.dataLayer || (window.dataLayer = []);
if (data.event) {
dataLayer.push({
'event': data.event,
'postMessageData': data
});
}
}catch(e){}
});
// Cross-browser event listener
function addEvent(el, evt, fn) {
if (el.addEventListener) {
el.addEventListener(evt, fn);
} else if (el.attachEvent) {
el.attachEvent('on' + evt, function(evt) {
fn.call(el, evt);
});
} else if (typeof el['on' + evt] === 'undefined' || el['on' + evt] === null) {
el['on' + evt] = function(evt) {
fn.call(el, evt);
};
}
}
})(window);
</script>
Trigger on parent (it's this that doesn't seem to be happening):
Form submission tag on parent:
Can anyone figure out what I've missed?
window.parent.postMessage(postObject, 'https://new.bokuntest.com');
try {
var postObject = JSON.stringify({
event: 'iframeFormSubmit',
form: 'Registration'
});
window.parent.postMessage(postObject, 'https://new.bokuntest.com');
} catch(e) {
window.console && window.console.log(e);
}
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);
});
});
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!
I'm following this tutorial on how to create a context menu when a user right clicks on selected text, the menu offers the user the option to send the text to a server:
http://vikku.info/programming/chrome-extension/get-selected-text-send-to-web-server-in-chrome-extension-communicate-between-content-script-and-background-page.htm#Comments
Here are the files:
The myscript.js file:
document.addEventListener('mouseup',function(event)
{
var sel = window.getSelection().toString();
alert('selection is '+sel)
if(sel.length)
chrome.extension.sendRequest({'message':'setText','data': sel},function(response){})
})
The background.html file:
<script>
var seltext = null;
chrome.extension.onRequest.addListener(function(request, sender, sendResponse)
{
switch(request.message)
{
case 'setText':
window.seltext = request.data
break;
default:
sendResponse({data: 'Invalid arguments'});
break;
}
});
function savetext(info,tab)
{
var jax = new XMLHttpRequest();
jax.open("POST","http://localhost/text/");
jax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
jax.send("text="+seltext);
jax.onreadystatechange = function() { if(jax.readyState==4) { alert(jax.responseText); }}
}
alert('here')
var contexts = ["selection"];
for (var i = 0; i < contexts.length; i++)
{
var context = contexts[i];
chrome.contextMenus.create({"title": "Send to Server", "contexts":[context], "onclick": savetext});
}
</script>
The manifest.json file:
<script>
var seltext = null;
chrome.extension.onRequest.addListener(function(request, sender, sendResponse)
{
switch(request.message)
{
case 'setText':
window.seltext = request.data
break;
default:
sendResponse({data: 'Invalid arguments'});
break;
}
});
function savetext(info,tab)
{
var jax = new XMLHttpRequest();
jax.open("POST","http://localhost/text/");
jax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
jax.send("text="+seltext);
jax.onreadystatechange = function() { if(jax.readyState==4) { alert(jax.responseText); }}
}
alert('here')
var contexts = ["selection"];
for (var i = 0; i < contexts.length; i++)
{
var context = contexts[i];
chrome.contextMenus.create({"title": "Send to Server", "contexts":[context], "onclick": savetext});
}
</script>
The popup.html file:
<body>
Just a sample popup
</body>
In myscript.js the function document.addEventListener('mouseup',function(event) is called every time a mouseup event is fired ed but I think this should be called if the user decides to send the request to the server. The context menu should be fired when the user right clicks selected text but I don't know why this is occurring? I needed to update the manifest version to 2.
i don't know, if i got you right...the user select text, press the right mouse button and than you want to do "something"...
try this:
'get the right mouse click
window.oncontextmenu = function ()
{
showSelection(); // call a function or do something here
return false; // cancel the default right click mouse menu (necessary)
}
'in the function get the selected text and do something
function showSelection()
{
var sel = window.getSelection().toString();
alert('selection is '+sel);
.....
}
i understood that your problem is that context menu is not firing... for that you need to do small changes to your manifest
add manifest vesrion as 2
change background_page as background which is a key and value as {scripts:["background.js"]}
create a new javascript file with name as background.js and copy the script tag which is there in background html.i added manifest and javascript. let me know if you found any difficulty.
manifest:
{
"name": "Word Reminder",
"version": "1.0",
"manifest_version": 2,
"description": "Word Reminder.",
"browser_action": {
"default_icon": "images/stick-man1.gif",
"popup":"popup.html"
},
"background": {
"scripts": ["background.js"]
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["js/myscript.js"]
}
],
"permissions": [
"http://*/*",
"https://*/*",
"contextMenus",
"tabs"
],
"content_security_policy": "script-src 'self' https://ajax.googleapis.com; object-src 'self'"
}
background.js(new file in the same folder should contain below code):
var seltext = null;
chrome.extension.onRequest.addListener(function(request, sender, sendResponse)
{
switch(request.message)
{
case 'setText':
window.seltext = request.data
break;
default:
sendResponse({data: 'Invalid arguments'});
break;
}
});
function savetext(info,tab)
{
var jax = new XMLHttpRequest();
jax.open("POST","http://localhost/text/");
jax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
jax.send("text="+seltext);
jax.onreadystatechange = function() { if(jax.readyState==4) { alert(jax.responseText); }}
}
var contexts = ["selection"];
for (var i = 0; i < contexts.length; i++)
{
var context = contexts[i];
chrome.contextMenus.create({"title": "Send to Server", "contexts":[context], "onclick": savetext});
}
I have a content script that runs from my chrome extension.
this script injects an iframe to the body of the current page.
i want to have the possibility to close the iframe from within the iframe.
how do i do this?
when i searched this issue on the web, almost each solution uses the window.parent.document property which for some reason is undefined in my case. any ideas?
EDIT - Code Sample:
in the HTML of the iframe:
<script type="text/javascript">
function frameClose() {
var windowFrames = window.parent.frames;
for (var i = 0; i < windowFrames.length; i++) {
var aFrame = windowFrames[i];
if (aFrame.name == 'myFrame') {
alert('in frame');
// WHAT TO DO HERE?
// window.parent.document is undefined
// aFrame.parentNode.removeChild(aFrame); - THIS DOES NOT WORK ALSO
break;
}
}
}
</script>
this is how i inject the iframe:
Extension.js
chrome.browserAction.onClicked.addListener(function(tab) {
chrome.tabs.executeScript(null, {
file : "/js/PushIFrame.js"
}, function() {
if (chrome.extension.lastError) {
}
});
});
and in PushIFrame.js i have:
chrome.extension.sendMessage({
action: "pushFrame",
source: pushIframe(document)
});
function pushIframe(document) {
var existingFrame = document.getElementById('bmarkFrame');
if (existingFrame == null) {
var temp = document.createElement('iframe');
temp.id = 'myFrame';
temp.name = 'myFrame';
temp.setAttribute('scrolling', 'no');
temp.setAttribute('allowtransparency', 'true');
temp.style.border = 'none';
temp.style.height = '100%';
temp.style.width = '100%';
temp.style.position = 'fixed';
temp.style.zIndex = 99999999;
temp.style.top = 0;
temp.style.left = 0;
temp.style.display = 'block';
temp.src = 'https://www.mysite.com/';
document.body.appendChild(temp);
}
else {
existingFrame.style.display = 'block';
}
}
Let the content script (say PushIframe.js) bind a message event to the main frame. Then, whenever you want to hide the iframe, call parent.postMessage to notify the main frame. This message is received by the content script, from where you can hide the frame (as defined in your function pushIframe).
// PushIframe.js:
addEventListener('message', function(ev) {
if (ev.data === 'closeIframe') {
pushIframe(document); // Your code
}
});
// Iframe:
<script>
function frameClose() {
parent.postMessage('closeIframe', '*');
}
</script>