I am creating a chrome extension which embeds an iframe on a website and it works well except when a user clicks on the iframe (or anything inside the iframe) and then tries to use the back button to navigate back to a previous page on the parent/actual site. When you attempt to go back the page just reloads the iframe (even when you press the back button many times, each time it just reloads the iframe). If the user doesn't click on the iframe (just mouseover) everything works as expected. Here is what my chrome extension is doing:
background.js:
chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status == 'complete') {
chrome.scripting.executeScript({
target: { tabId: tab.id },
function: createIframe
});
}
});
function createIframe() {
var location = document.getElementById(id of location);
var embed = document.createElement("iframe");
embed.setAttribute('src', link);
location.appendChild(embed.cloneNode(true));
}
Responses to similar problems said the issue was setting the src link using setAttribute and that this method added the iframe loading to the browser history. To fix this they suggest using iframe.contentWindow.location.replace(link);. I tried doing this, but the iframe didn't even load the link content (not sure if replace requires a location to be set already):
embed.setAttribute('id', 'uniqueid');
var frame = document.getElementById('uniqueid');
frame.contentWindow.location.replace(link);
I am new to web development (and chrome extension development) and any help would be greatly appreciated! Thanks in advance.
Related
I am trying to build this chrome extension that only displays the popup when I am on a youtube video page. However, I am having a lot of difficulties doing this and used many approaches.
My latest approach is to use chrome.action.onClicked and check if the URL contains https://youtube.com/watch. Then I would use chrome.action.setPopup to my HTML file. This works on all pages until when I click on the extension while on a youtube video page, then it would just show on every single page.
Here is my background.js:
chrome.action.onClicked.addListener((tab) => {
console.log(tab.tabId);
if (tab.url.includes("https://www.youtube.com/watch") == true) {
chrome.action.setPopup({ tabId: tab.tabId, popup: "/Pages/index.html" });
} else if (tab.url.includes("https://www.youtube.com/watch") == false) {
chrome.action.setPopup({ tabId: tab.tabId, popup: "" });
}
});
I think that it is not working because after setting the popup, that means it does not check the onClicked event anymore (specified here).
Any help would be much appreciated!
It's not tab.tabId but tab.id. You can check for it. And setPopup when onClicked, you have to click the extension twice will the popup show up.
I have an iframe that links to another internal web application.
There's a side panel with a list of links that changes the src of the iframe. Sometimes if there's a lot of data, the iframe site takes a while to load. I want to put a spinner icon when a link is clicked and hide it when the frame is loaded.
I change the src using $('#myiframe').attr('src', urlVar) in a click function for the links. I can show the spinner on click.
The problem is, how do I hide it? How do I find out that the iframe has finished loading?
I tried using $('#myiframe').load(function() { }) but that only works on the initial load (i.e. for the first link I click), not for subsequent loads (if I click on another link).
This javascript works for me :
function loadNewUrl (url){
if(url === undefined) url = 'http://example.com?v=' + Math.random();
var ifr = document.getElementById('myiframe');
ifr.setAttribute('src',url);
ifr.onload = function() {
alert('loaded');
};
}
This may be a dupe of the question at Google Chrome DevTools Extension - Detect Page Change, but it's been sitting for over a year without a real answer, and maybe my question will provide some new insight into the problem.
I've written a Chrome Extension which inserts a sidebar panel into DevTools. The side panel lists the dataLayer events, a user can click on the desired event and then use the element picker to select another element on the page, and the plugin displays the path between the elements in dot notation.
Here's the link to the Github project: https://github.com/gruebleenagency/gtm-data-layer-sifter
It works as I'd like it to normally, but if you navigate to another page, the sidebar is not initialized again, so it displays the info from the previous page.
You can see that I have this in my background.js file:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
reloadExtension();
}
});
function reloadExtension() {
// ???
}
I'm wondering if there's any way to make the sidebar reload at this point? Or am I going about this in the wrong way? I've spent a lot of time messing around with this trying to get it to work, but nothing seems to do the trick.
Thanks for any and all help.
Here's my solution. It's very possible that this isn't the way it should be done, but I don't have the time to rewrite the whole plugin at the moment, so it'll have to do for now. Any suggestions for how I should have done it would be greatly appreciated. And maybe it will be helpful to someone in a different situation.
Essentially, listen to the tabs.onUpdated event waiting for the 'complete' status, which indicates we've navigated to a new page. Then send message to Devtools.js to refresh the side panel, by setting its page to 'panel.html' again.
In background.js:
chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
if (changeInfo.status == 'complete') {
reloadExtension(port);
}
});
function reloadExtension(port) {
var message = {action: "reloadExtension"};
port.postMessage(message);
}
In Devtools.js:
var sb;
createSidebar();
function createSidebar() {
chrome.devtools.panels.elements.createSidebarPane("GTM dataLayer Sifter", function(sidebar) {
sb = sidebar;
sb.setPage("panel.html");
});
}
var port = chrome.extension.connect({
name: "Devtools.js Communication"
});
// Listen to messages from the background page
port.onMessage.addListener(function(message) {
if(message.action == "reloadExtension"){
sb.setPage("panel.html");
}
});
You can do it by listen onNavigated event:
In Devtools.js
chrome.devtools.network.onNavigated.addListener(() => {
console.log('Inspected page reloaded');
});
I've been working on a Frame busting buster (what's in a name, hehe), which kept my users on my page and open a new window with the target URL. I'm using a Lightbox script to display iframes, this is what I'm doing:
1) Added an event for all .lightbox clicks, f.e:
$('.lightbox').live("click", function(e) {
e.preventDefault();
$('#redirectURL').val($(this).attr('href'));
$(this).lightbox();
}
2) Added a frame busting buster:
<script type="text/javascript">
var prevent_bust = 0
window.onbeforeunload = function() { prevent_bust++ }
setInterval(function() {
if (prevent_bust > 0) {
prevent_bust -= 2
window.top.location = 'http://server-which-responds-with-204.com'
}
}, 1)
</script>
3) Modified the frame busting buster code to fit my needs, which are:
detect if an iframe wants to change the window.top.location
if so, prevent this from happening using the 204 server respond
open a new page: window.open( $('#redirectURL', '_blank' );
close lightbox: $('.jquery-lightbox-button-close').click();
So far, this is what I've come up with:
var prevent_bust = 0
window.onbeforeunload = function() { prevent_bust++ }
setInterval(function() {
if (prevent_bust > 0) {
prevent_bust -= 2;
redirectURL = $('#redirectURL').val();
if(redirectURL != "") {
window.top.location = 'http://www.****.com/ajax/nocontent.php';
window.open(redirectURL, "_blank");
$('.jquery-lightbox-button-close').click();
$('#redirectURL').val('');
} else {
window.top.location = 'http://www.****.com/ajax/nocontent.php';
}
}
}, 1);
// EDIT: Before I forget, 'nocontent.php' is a file that returns a 204 header
For Firefox it acts as I programmed it, if there's a change detected in the window.top.location it opens a new frame/page and prevents the iframe from reloading the top location and to round it up, it closes the jQuery lightbox.
Safari/Chrome act similar, they open a new browser screen (not sure if theres an option to say target="_newtab" or something?). Only bad thing is they do not really display a message of the popup is blocked, but I can work around that by displaying a popup balloon on my website with a link to the page.
Internet Explorer is, what a shocker, the only black sheep left.. IE does not open a new popup, nor blocks the window.top.location reset by the iFrame and simply continues refreshing the complete page to the '#targetURL'. It does the same with the default busting code.. so it's not because of some of my edits.
Anyone who is able to spot a mistake in my code?
Also, I would need a little modification that sees if the request has been made by an iframe or by the user itself, because now there is really NO option for a user to leave my page by changing the address in the toolbar or by clicking a link, which is not really needed LOL.
Thanks in advance.
PENDO, I tried to simulate the whole process you described, ligthbox-jquery, javascript their own codes and controls opening pages via lightbox. I could not simulate at all, and as time is running out I'm sending a suggestion to broaden the range of possibilities and solutions.
I suggest replacing the redirect page:
...
redirectUrl = $ ('# redirectUrl'). val ();
...
window.top.location = 'http://www .****. with / ajax / nocontent.php';
window.open (redirectUrl, "_blank");
Replaced with a DIV container that simulates a page, using ajax calls and taking the content and overwritten the contents of the DIV.
...
$.post(redirectoURL /* or desired URL */, function(data) {
$('DIV.simulateContent').html(data);
});
...
or
...
$('DIV.simulateContent').load(redirectoURL);
...
This approach also avoids the problem of preventing the user from even leaving your page using the address bar (as you yourself mentioned).
Sorry, let me give you a complete solution, but time prevented me.
PENDO, a little more work on alternatives to the problem, I found a customizable jQuery lightbox plugin for working with custom windows yet (iframe, html, inline ajax etc.). Maybe it will help. The following link:
http://jacklmoore.com/colorbox/
If you don't need javascript running in your iframe in IE, you can set the iframe security attribute :
<iframe security="restricted" src="http://domain.com" />
http://msdn.microsoft.com/en-us/library/ms534622(v=VS.85).aspx
I got this problem during development of my own addon, but I get the same with the reddit example, so I'll use that for simplicity.
Using the exact code from the example found here, this is what happens.
Reddit Example
This example add-on creates a panel containing the mobile version of Reddit. When the user clicks on the title of a story in the panel, the add-on opens the linked story in a new tab in the main browser window.
To accomplish this the add-on needs to run a content script in the context of the Reddit page which intercepts mouse clicks on each title link and fetches the link's target URL. The content script then needs to send the URL to the add-on script.
main.js:
var data = require("self").data;
var reddit_panel = require("panel").Panel({
width: 240,
height: 320,
contentURL: "http://www.reddit.com/.mobile?keep_extension=True",
contentScriptFile: [data.url("jquery-1.4.4.min.js"),
data.url("panel.js")]
});
reddit_panel.port.on("click", function(url) {
require("tabs").open(url);
});
require("widget").Widget({
id: "open-reddit-btn",
label: "Reddit",
contentURL: "http://www.reddit.com/static/favicon.ico",
panel: reddit_panel
});
panel.js:
$(window).click(function (event) {
var t = event.target;
// Don't intercept the click if it isn't on a link.
if (t.nodeName != "A")
return;
// Don't intercept the click if it was on one of the links in the header
// or next/previous footer, since those links should load in the panel itself.
if ($(t).parents('#header').length || $(t).parents('.nextprev').length)
return;
// Intercept the click, passing it to the addon, which will load it in a tab.
event.stopPropagation();
event.preventDefault();
self.port.emit('click', t.toString());
});
The icon is displayed in the bar, and clicking it launches the panel. Clicking a link within the panel opens it in a new tab - just as described and expected.
Clicking the "next page" link within the tab successfully fetches the next page, within the panel - as expected.
Clicking a link on the 2nd page does NOT open it in a tab, it opens it WITHIN the panel.
Here's my guess: When the page reloads within the panel, it does not reload the script specified in the contentScriptFile. Does anyone else experience this? And is there a workaround?
I'm using SDK 1.0 and FF 5.0
Question cross-posted on the Addon forum here
Recieved this answer at the Mozilla forum, and will post here as well for future reference.
Perhaps you are seeing Bug 667664 - Panel content scripts don't work after reloading or changing location. I think the workaround is to load the content in an iframe.
Which I believe might be the case, I'll try this during the day and report back.
EDIT: iframe seems to do the trick