The crossrider sidepanel is simply an iframe (you can use js-injected html, but I'm interested in using an iframe to reduce interference with the rest of the page). I'm having trouble getting any interaction between my browser extension and the iframe at all.
I see no point at all in adding a sidepanel with an extension unless you can do some basic JS communication. In this case I want a few options, checkboxes etc, in the iframe which control the extension. Since this plugin exists, I'm assuming there must be a way.
Ideally I'd like to have some basic input handling js in the child iframe and have it send back the odd save/load command. Is the answer really some form of message passing? If so which API should I be using here?
I believe this is related: Accessing iframe from chrome extension
[EDIT]
OK, so I've tried a few things...
It seems the expected usage is to host the iframe's html content somewhere. A bit strange considering it should be local and part of the extension. What happens if you want to view some pages offline?? This is just silly and I'm dismissing it as an option. Why waste resources hosting something that should just be available locally.
The alternative is to provide the HTML that goes in the sidebar. Note that this HTML doesn't get put in an iframe. I like the idea of an iframe because it keeps the CSS and JS very separate, so there's minimal interference between a page and your extension.
So I tried creating an iframe via the html sidebar attribute with and ID and injected the content after a 100ms delay using myiframe.contentWindow.document.open/writeln/close(). This works fine on chrome but fails in firefox with a security error (The operation is insecure on open()).
Another way is to provide the iframe content via the src url (for the sidebar I use a data address for the url attribute): Html code as IFRAME source rather than a URL. This works in firefox but results in a CORS error in chrome: The frame requesting access has a protocol of "http", the frame being accessed has a protocol of "data". Protocols must match. and Warning: Blocked a frame with origin "http://localhost" from accessing a cross-origin frame. Function-name: appAPI.message.addListener
These CORS issues strike me as really daft. It's all my code coming from the same extension, injected into the same page. There's no cross origin happening, I created the damn thing. If I have the power to change the origin, then it's not secure in the first place so why bother.
Assuming you are using the url sidebar property to load your sidebar's HTML (i.e. a hosted web page), you can use the extension's Run in Iframe feature to communicate between the iframe extension and the parent window's extension.
To achieve this, first enable the extension to run in iframes (Settings > Run in Iframes) and then you can use the extension.js to load your sidebar and handle messaging. For example, the following code loads a page that has a button with identification btnSave:
Hosted web page file:
<html>
<head>
</head>
<body>
<div id="mySidebar">
My sidebar form
<br />
<button id="btnSave">Save</button>
</div>
</body>
</html>
extension.js file:
appAPI.ready(function($) {
// Check if running in iframe and the sidebar page loaded
if (appAPI.dom.isIframe() && $('#mySidebar').length) {
// Set click handler for button to send message to parent window
$('#btnSave').click(function() {
appAPI.message.toCurrentTabWindow({
type:'save',
data:'My save data'
});
});
// End of Iframe code ... exit
return;
}
// Parent window message listener
appAPI.message.addListener(function(msg) {
if (msg.type === 'save') {
console.log('Extn:: Parent received data: ' +
appAPI.JSON.stringify(msg.data));
}
});
// Create the sidebar
var sidebar = new appAPI.sidebar({
position:'right',
url: 'http://yourdomain.com/sidebar_page.html',
title:{
content:'Sidebar Title',
close:true
},
opacity:1.0,
width:'300px',
height:'650px',
preloader:true,
sticky:true,
slide:150,
openAction:['click', 'mouseover'],
closeAction:'click',
theme:'default',
scrollbars:false,
openOnInstall:true,
events:{
onShow:function () {
console.log("Extn:: Show sidebar event triggered");
},
onHide:function () {
console.log("Extn:: Hide sidebar event triggered");
}
}
});
});
However, if you are using the html sidebar property to load your sidebar's HTML, then this solution will not work since the extension does not run in this context. However, you may be able to utilize the methods described in the StackOverflow thread you quoted to communicate with the parent window (this would be browser specific) that in turn can communicate with the extension using our CrossriderAPI event.
[Disclaimer: I am a Crossrider employee]
Related
I'm trying to create a simple website blocker in chrome, but after blocking a URL (for example https://example.com), I'd like to render my own custom HTML file that tells the user that the page has been blocked. It's important to me that when the custom blocked page is shown, the URL is still example.com.
I figured out how to block the URL using the webRequest API, but the only way I can see to show a custom page saying that the website has been blocked is to redirect the user, which obviously won't work for my goals.
Instead of redirecting/blocking try stopping the page and show your UI as standard DOM.
background script:
chrome.webRequest.onHeadersReceived.addListener(info => {
chrome.tabs.executeScript(info.tabId, {
file: 'stop.js',
runAt: 'document_start',
});
}, {
urls: ['*://foo/*'],
types: ['main_frame'],
});
stop.js - running as a content script
window.stop();
// reset DOM
document.write('<!DOCTYPE html><html>');
// create your UI
document.body.textContent = 'blocked';
You can load your UI in an iframe pointing to an html file declared in web_accessible_resources.
I had the same issue and I was able to fix it by specifying my custom html page in "web_accessible_resources" in the manifest.
For further reading, check here
I have a website which is built using WP and uses SSL. On one of the page on my website, I have added an iframe call to another http website.
Here is my iframe call:
<div class="embed-responsive embed-responsive-16by9">
<iframe src="//childwebsite.com/" target="_blank"></iframe>
</div>
The iframe is displayed properly. Now when you click on anything inside the iframe, Chrome displays a message saying
Mixed Content: The page at 'https://parentwebsite.com' was loaded over HTTPS, but requested an insecure resource 'http://childwebsite.com'. This request has been blocked; the content must be served over HTTPS.
What I am looking for is when a user clicks inside an iframe, open a new tab in the browser and let the user be redirected to a particular on the childwebsite.
I tried adding target="_blank" to the iframe but it did not work.
I added the following JS also but it did not work
//pass the iframe to this iframe getting function
function iframeRef( frameRef ) {
return frameRef.contentWindow ? frameRef.contentWindow.document : frameRef.contentDocument
}
//Get Iframe
var inside = iframeRef( document.getElementById('smugmugGallery') );
//Get all links
var links = inside.getElementsByTagName('input');
//Loop throught links and set their attributes
for (var i = 0 ; i<links.length ; i++){
links[i].setAttribute('target','_blank');
}
Any help will be appreciated.
You have two issues here. An SSL issue, and a cross domain issue.
Your SSL issue can only be solved by serving the iframed content via SSL or serving the parent page via non-SSL. This will remove the security alerts you are seeing.
You cannot assert control over iframed content if it comes from another domain, well at least not easily for cross browser purposes.
From the Mozilla dev site:
Scripts trying to access a frame's content are subject to the
same-origin policy, and cannot access most of the properties in the
other window object if it was loaded from a different domain. This
also applies to a script inside a frame trying to access its parent
window. Cross-domain communication can still be achieved with
window.postMessage.
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/iframe#Scripting
Use base tag in iframe and try once.
<base target="_blank" />
you can see more about Base tag here
In short , I'm developing a google chrome extension , when I add any url starting with http:// to source attribute to an iframe, I get a message like :
[blocked] The page at 'https://www.facebook.com/' was loaded over
HTTPS, but ran insecure content from 'http://youtu.be/m0QxDjRdIq4':
this content should also be loaded over HTTPS.
and I don't see the content in the iframe !
so how can I overcome this ?
what I want to achieve is that : I hide facebook adds , and in its place I added an iframe instead, I detect when the mouse is hovering over a link contained in a post, then I want to show the link's content in an iframe.
What are my possible alternatives? I don't need to enable showing insecure content in chrome because it is a chrome extension that I will publish!
It seems that the security limit is strict, so we need a way to work around that.
What if you could load the page using other means than an <iframe> and insert it into the page afterwards? There are multiple ways to do that, ranging from more practical to less realistic.
You can use the Chrome captureVisibleTab API to generate a screenshot of a website as an image, exactly what you need. It sounds like you need a visible tab to use this API, but you can actually specify any Chrome window as a target and you can create Chrome windows unfocused and hidden behind the edge of the screen.
If captureVisibleTab provides trouble in step 2, there is also pageCapture API to get an entire page as a single content object.
You can also use a server to create screenshots. Serve a simple application over HTTPS that uses PhantomJS to create a screenshot. An advantage of this approach is your server is likely to be much faster at screenshot generation. The disadvantage is you need to pay for the server.
You could also use xhr in your extension background process (which is not limited by the security limitation) to get the HTML. This wouldn't get any resources, but that could be a beneficial thing if you want a very quick if inaccurate screenshot. Just load HTML, parse and detect links to stylesheets, download them and inject those stylesheets into the HTML as <style> tags.
The resulting HTML can be injected to the <iframe> manually. You could even inject scripts and images this way, but that would be harder and less useful, since you need a quick screenshot of how the page looks like.
I think using built-in Chrome functionality for screenshots is the best bet, if only you can make the user experience good enough.
First and stupid way: change http in link on https. But youtube and I think many other sites don't allow to show their content in iframes. try it and you get Refused to display 'link' in a frame because it set 'X-Frame-Options' to 'SAMEORIGIN'.
Second and at least stupid way: remove protocol from link, like //youtu.be/m0QxDjRdIq4 and you get protocol, that on this page. But a situation similar to the previous.
Third way for youtube only: you can generate iframe with src like //www.youtube.com/embed/m0QxDjRdIq4 and user can see the video.
Fourth way, not for all sites: use site API's - not a best solution, but like a option.
Fifth way, but impossible (I think): try to get page's content with javascript and regenerate it in way, that you need.
Sixth way, needs powerfull server: create an service on your server, which will download pages and resend it to users. One problem - linear dependence server's power of requests.
Seventh way, I forgot that it's extension: you can open link in another tab/window, get it content, close tab/window and show content in tab that you need.
Eigth way, the best, I think: use YAHOO yql like this:
$.getJSON("https://query.yahooapis.com/v1/public/yql?q=select"
+"* from html where url='youtube.com/watch?v=m0QxDjRdIq4'"
+"&format=json&diagnostics=true&callback=?"
, function (data, textStatus, jqxhr) {
// process data
}
}
Demo on jsFiddle
I am using the following code to implement a hotkey for my Chrome extension:
// content script:
window.addEventListener("keydown", function(event) {
if (event.ctrlKey && event.keyCode == 81) {alert('Ctrl+Q Pressed!');}
}, false);
Since inserting the following line in the manifest file it has worked in most situations, even when iFrames are selected:
...
"content_scripts": [
{
"all_frames": true
...
For example with http://danish.typeit.org, the hotkey even now works when typing with that and facebook personal messages too. Everywhere it seems except when composing emails using gmail, yahoo mail or gmx. While the composition box is selected, the hotkey doesn't work. This is a disappointment as I was hoping people would use my extension to aid with writing emails. And Twitter, it does not work when typing on Twitter, either.
I think the reason that the content script is not being loaded for the editor iframe even when you have all_frames specified is that the content scripts only get applied to iframes that are present in the markup when the containing page is loaded.
In the case of the gmail page, there are multiple iframes on the page, some that are present in the markup of the containing page (which the content script gets applied to) and then the one for the editor, which is created by JavaScript after the page is loaded.
Even if you were to try and wait for the JavaScript on the page to load the iframe for the editor the JavaScript in the content script would not be able to access it because accessing the contentWindow object of an iframe is not allowed in content scripts.
A long shot might be to inject a JavaScript file into the DOM that then executes the logic you have in the content script.
The content script might be something like:
document.body.appendChild(document.createElement("script")).src = "http://external/file/javascript.js";
Then the contents of the remote JavaScript file could try and get access to the editor iframe, you might need to use a setInterval until the element is created.
// These are the IDs gmail uses, each mail app would be different
document.getElementById("canvas_frame").contentWindow.document.getElementById(":nt")
I want to track what happens inside an iframe when a user clicks on links in the IFrame. The page that contains the iframe (the parent) is to track the user´s navigation through the page in the iframe. Both pages will be hosted on the same toplevel domain, although the subdomains will differ.
I need the parent page to be notified of every click, but I do not have direct control over the pages I load into the iframe.
Is adding an onclick to all the links whenever the page in the iframe is loaded possible? How would I go about doing this?
This would be the "template" on which to build:
<html>
<script language="javascript">
var currentURL;
</script>
<body>
<iframe id="container" width="500" height="500" src="http://subdomain.parentdomain.com"/>
</body>
Iframe CrossDomain access needs to be the same domain, subdomain, and port.
If you had them on the same domain, you could bind click event handlers on all the links, then when they are clicked log a click to something like google analytics, your database, etc.
I do not have direct control over the pages I load into the iframe
That's your blocker. If you can augment the code within the remote pages, you can use postMessage and the iframe fragment identifier hack to get browser coverage.
Fortunately, someone already did the dirty work for you:
http://easyxdm.net/
http://consumer.easyxdm.net/c/
http://www.codeproject.com/KB/scripting/easyXDM.aspx?msg=3153511
I am going to use an AJAX-Proxy to have the content (as far as the browser is concerned) come from my domain. This will solve all the cross domain scripting issues that CodeJoust mentioned. Speed of delivery might be a problem due to the overhead I will be generating, but that will have to be seen.
I will probably move along the lines of this Stackoverflow Question:
"Apply “onclick” to all elements in an iFrame"
Regarding legal issues pertaining to proxying and changing the content of pages dynamically, it will have to be checked. I believe that tracking users that give their express consent is, from an ethical standpoint, unproblematic.
With jQuery it would be easy.
$(document).ready(function(){
var iframeWindow = $('#container')[0].contentWindow;
$(iframeWindow).load(function(){
$(this).find('a').click(top.myClickHandler);
});
}
function myClickHandler(){
/* Do something */
}