I've read all the cross domain iframe posts here (my thanks to all of you!) and elsewhere.
The postMessage script at cross-domain iframe resizer? works beautifully in Firefox 5 and up. It resizes the iframe every time a page is clicked within the iframe perfectly.
But it doesn't resize at all in IE (7 8 or 9) on my computer. I checked the security settings and the one in IE for access across domains was checked to enable.
Does postMessage not work in IE? - Or is there something else that needs to be added? thanks
It's a great script from thomax - it also works on so you can use iframes on mobile - iphones and android
For IE7 and IE8, you have to use window.attachEvent instead of window.addEventListener
It should also be onmessage instead of message (see below) ps you also need to do the same on the server with the content posting its size
<script type="text/javascript">
if (window.addEventListener)
{
function resizeCrossDomainIframe(id) {
var iframe = document.getElementById(id);
window.addEventListener('message', function(event) {
var height = parseInt(event.data) + 32;
iframe.height = height + "px";
}, false);
}
}
else if (window.attachEvent)
{
function resizeCrossDomainIframe(id) {
var iframe = document.getElementById(id);
window.attachEvent('onmessage', function(event) {
var height = parseInt(event.data) + 32;
iframe.height = height + "px";
}, false);
}
}
</script>
Using Peter's code and some ideas from here, you could separate out the compatibility from the executable code, and add some cross-site validation.
<script type="text/javascript">
// Create browser compatible event handler.
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen for a message from the iframe.
eventer(messageEvent, function(e) {
if (e.origin !== 'http://yourdomain.com' || isNaN(e.data)) return;
document.getElementById('iframe_id_goes_here').style.height = e.data + 'px';
}, false);
</script>
Also, for completeness, you could use the following code within the iframe whenever you want to trigger the resize.
parent.postMessage(document.body.offsetHeight, '*');
You can use the implementation of Ben Alman. Here is an example of cross-domain communication, including an example of iframe resize.
http://benalman.com/code/projects/jquery-postmessage/examples/iframe/
According to the documentation, it works on Internet Explorer 6-8, Firefox 3, Safari 3-4, Chrome, Opera 9.
Having looked a lots of different solutions to this I ended up writing a simple jQuery plugin to take a account of a number of different use cases. As I needed a solution that supported multiple user generated iFrames on a portal page, supported browser resizes and could cope with the host page JavaScript loading after the iFrame. I also added support for sizing to width and a callback function and allow the override of the body.margin, as you will likely want to have this set to zero.
https://github.com/davidjbradshaw/iframe-resizer
The host page users jQuery, the iframe code is just a little self-contained JavaScript, so that it's a good guest on other people pages.
The jQuery is then initialised on the host page and has the following available options. More details on what these do on the GitHub page.
$('iframe').iFrameSizer({
log: false,
contentWindowBodyMargin:8,
doHeight:true,
doWidth:false,
enablePublicMethods:false,
interval:33,
autoResize: true,
callback:function(messageData){
$('p#callback').html('<b>Frame ID:</b> ' + messageData.iframe.id +
' <b>Height:</b> ' + messageData.height +
' <b>Width:</b> ' + messageData.width +
' <b>Event type:</b> ' + messageData.type);
}
});
If you set enablePublicMethods, it gives you access in the iframe to manually set the iFrame size and even remove the iframe from the host page.
Related
I've been trying to figure out how to open an URL that you open within the Instagram app, in an external browser (Safari, Chrome) rather than the in-build Instagram-browser.
i want that link in website part of instagram asks to leave Instagram app and opens external browser visiting website.
I tried a lot of things, like using window.open with _blank, _system, etc. Also tried these within a
This is not possible, as it is a deliberate choice of the Instagram developers to use their own browser control.
You can detect Instagram in-app browser
navigator.userAgent.includes("Instagram")
and put link like that
<a href={location.href} target='_blank' download>Open in browser</a>
All magic in 'download' key word. When user clicks the link it will be redirected to the native browser.
It work perfect in android. I haven't tested it on iOS
I found an interesting article that talks about it,
try to work around with this bit of code to make the Instagram’s in-app browser redirect to your website
<script>
if(navigator.userAgent.includes("Instagram")){
window.location.href = "https://mywebsite.com/DummyBytes";
}
</script>
For more information have a look at the article:
https://medium.com/#sasan.salem/opening-of-your-website-in-the-viewers-external-browser-automatically-instead-of-instagram-s-8aca5ee7e22f
Opening of your website in the viewer’s external browser automatically instead of Instagram’s in-app browser (on Android devices).
You can solve it by acting as a file to be downloaded, then the in-app browser will redirect you to the mobile browser.
not working on iPhone. :(
PHP
<?php
$userAgent = $_SERVER['HTTP_USER_AGENT'];
if (strpos($userAgent, 'Instagram')) {
header('Content-type: application/pdf');
header('Content-Disposition: inline; filename= blablabla');
header('Content-Transfer-Encoding: binary');
header('Accept-Ranges: bytes');
#readfile($file);
die();
}
?>
ASP.NET Web API:
namespace DotNet.Controller
{
public class DummyBytesController : ApiController
{
[HttpGet]
public HttpResponseMessage Get()
{
HttpResponseMessage Response;
string UserAgent = HttpContext.Current.Request.UserAgent;
if(UserAgent.Contains("Instagram"))
{
Response = new HttpResponseMessage(HttpStatusCode.OK);
Response.Content = new ByteArrayContent(new byte[50]);
Response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
return Response;
}
else
{
Response = Request.CreateResponse(HttpStatusCode.Redirect);
Response.Headers.Location = new Uri("https://mywebsite.com");
return Response;
}
}
}
}
You can add this script to head to redirect to chrome:
<script>
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
var str = navigator.userAgent;
var instagram = str.indexOf("Instagram");
var facebook = str.indexOf("FB");
if (/android/i.test(userAgent) && (instagram != -1 || facebook != -1) ) {
document.write("<a target=\"_blank\" href=\"https://yourdomain.com\" download id=\"open-browser-url\">Please wait. Proceed to Chrome</a>");
window.stop();
let input = document.getElementById('open-browser-url');
if (input) {
input.click();
}
}
</script>
Actually, there is a possibility.
You first access the link with the in-app browser, then you click on the 3-dots button on the right top of the page and select "open in Chrome".
I'm working on a NodeJS/ExpressJS application using JQuery Mobile (JQM). I'm having trouble redirecting from the backend. My app dynamically generates buttons
<button class=\"setAttndingbtn btn btn-primary\" value=\"" + curr.place_id + "\">Attending: " + numAttending.numAttnd + " people are going</button>
after a $.getJSON search is made. Using promises/setTimeout, the following handler is attached to all buttons:
$('.setAttndingbtn').click(function(){
var buttonsir = $(this); //Store this button reference
if($(this).html().slice(0,1) == 'A'){ //Check the button's state
$.getJSON('/api/attending/' + $(this).val(), function(data){ //Ajax
$(buttonsir).text("You are attending! " + data.numAttnd + " people are going"); //Change state
});
} else {
$.getJSON('/api/attending/rmv/' + $(this).val(), function(data){
$(buttonsir).text("Attending: " + data.numAttnd + " people are going");
});
}
});
The relevant routes are here:
function isLoggedIn(req, res, next){
if(req.isAuthenticated()){
return next();
} else {
res.redirect('/login');
}
}
app.route('/login')
.get(function(req, res){
res.sendFile(p + "/public/login.html");
});
app.route('/api/attending/:number')
.get(isLoggedIn, searchServerInstance.setAttending);
On the backend, when an "Attending" button is clicked, I want to check if the user is logged in and if not, redirect them to the login page. When I run the code as is, in Firefox's Firebug console, I see the GET request and if I expand it, in the "Response" section, the HTML code to my login page is displayed. But the page doesn't actually load the file.
My /login.html has <div data-role="page">, header, and content tags, as JQM recommends. I've tried including the entire login page in my /index.html, but attempting to use res.redirect("/public/index.html#page2") results in a "file not found".
Is it possible to use Node/Express to tell JQM which <div data-role="page" id="page1"> to load? Is there a way to force JQM to load /login.html from the server-side, the way rel="external" allows for? Or will I have to ditch JQM?
Reading through the JQM documentation, I've figured out some ways to do this. For anyone else who encounters it, here's what I believe I understand:
If you don't care about maintaining the integrity of the single-page, you can look into turning off JQM's defaults, like ajaxEnabled, which turns off JQM's hash listening and ajax, loading URLs normally. I don't know if this works with Express's res.redirect because I haven't tried it.
What I opted to do was to replace res.redirect('/login.html') with a custom JSON response res.send({loginState: "LOGIN"}). Then, on the client side, within my $.getJSON request in the $('.setAttndngbtn') listener, i put the following code:
.
if(data.loginstate !== "LOGIN"){
$(buttonsir).text("You are attending! " + data.numAttnd + " people are going");
} else {
$(":mobile-pagecontainer").pagecontainer("change", '#page2');
}
And it works just fine! Here is the JQM documentation on the pagecontainer widget that allows in-page redirection with the change method or external redirection with the load method.
I'm trying to use vk.messages api in chrome app like this:
app.login = function () {
var link = 'https://oauth.vk.com/authorize?' +
'client_id=4837072' +
'&scope=friends,docs,status,messages,notifications,' +
'&redirect_uri=' + 'https://oauth.vk.com/blank.html' +
'&display=popup' +
'&v=API_VERSION' +
'&response_type=token';
var width = 655;
var height = 539;
var left = (screen.width / 2) - (width / 2);
var top = (screen.height / 2) - (height / 2);
chrome.identity.launchWebAuthFlow({
'url': link,
'interactive': true
}, function (redirect_url) {
// redirect_url is undefined
console.log(redirect_url);
});
};
It needs to set auth redirect_uri this way "https://oauth.vk.com/blank.html", but chrome.identity api uses "https://.chromiumapp.org/". So, vk auth window is showed and redirect works, but chrome can't determine auth redirect, and doesn't call back with redirect url. Is there any other way to get redirect url in chrome app?
Well, I see where you're going with "it needs to set redirect_uri this way":
redirect_uri=https://oauth.vk.com/blank.html
It is a mandatory condition for methods which descriptions say that they are available only for Desktop applications.
I'm afraid there is no way to override the URL used by identity API.
In this case, you can go kind of the same route Silver Bird Twitter client went: inject a Content Script in the target address. From there you can extract the tokens needed.
Edit: I forgot that you are writing a Chrome app. You should then try using <webview> and its script injection capabilities.
This means you'll have to do OAuth without help from chrome.identity yourself, but at least it's a solution.
Is it possible to build an 'incognito mode' for loading background web-pages in a browser extension?
I am writing a non-IE cross-browser extension that periodically checks web-pages on the user's behalf. There are two requirements:
Page checks are done in the background, to be as unobtrusive as possible. I believe this could be done by opening the page in a new unfocussed browser tab, or hidden in a sandboxed iframe in the extension's background page.
The page checks should operate in 'incognito mode', and not use/update the user's cookies, history, or local storage. This is to stop the checks polluting the user's actual browsing behavior as much as possible.
Any thoughts on how to implement this 'incognito mode'?
It would ideally work in as many browser types as possible (not IE).
My current ideas are:
Filter out cookie headers from incoming/outgoing http requests associated with the page checks (if I can identify all of these) (not possible in Safari?)
After each page check, filter out the page from the user's history.
Useful SO questions I've found:
Chrome extension: loading a hidden page (without iframe)
Firefox addon development, open a hidden web browser
Identify requests originating in the hiddenDOMWindow (or one of its iframes)
var Cu = Components.utils;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/devtools/Console.jsm');
var win = Services.appShell.hiddenDOMWindow
var iframe = win.document.createElementNS('http://www.w3.org/1999/xhtml', 'iframe');
iframe.addEventListener('DOMContentLoaded', function(e) {
var win = e.originalTarget.defaultView;
console.log('done loaded', e.document.location);
if (win.frameElement && win.frameElement != iframe) {
//its a frame in the in iframe that load
}
}, false);
win.document.documentElement.appendChild(iframe);
must keep a global var reference to iframe we added.
then you can change the iframe location like this, and when its loaded it triggers the event listener above
iframe.contentWindow.location = 'http://www.bing.com/'
that DOMContentLoaded identifies all things loaded in that iframe. if the page has frames it detects that too.
to remove from history, into the DOMContentLoaded function use the history service to remove win.location from history:
https://developer.mozilla.org/en-US/docs/Using_the_Places_history_service
now to strip the cookies from requests in that page use this code:
const {classes: Cc, Constructor: CC, interfaces: Ci, utils: Cu, results: Cr, manager: Cm} = Components;
Cu.import('resource://gre/modules/Services.jsm');
var myTabToSpoofIn = Services.wm.getMostRecentBrowser('navigator:browser').gBrowser.tabContainer[0]; //will spoof in the first tab of your browser
var httpRequestObserver = {
observe: function (subject, topic, data) {
var httpChannel, requestURL;
if (topic == "http-on-modify-request") {
httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);
var goodies = loadContextGoodies(httpChannel)
if (goodies) {
if (goodies.contentWindow.top == iframe.contentWindow.top) {
httpChannel.setRequestHeader('Cookie', '', false);
} else {
//this page load isnt in our iframe so ignore it
}
}
}
}
};
Services.obs.addObserver(httpRequestObserver, "http-on-modify-request", false);
//Services.obs.removeObserver(httpRequestObserver, "http-on-modify-request", false); //run this on shudown of your addon otherwise the observer stags registerd
//this function gets the contentWindow and other good stuff from loadContext of httpChannel
function loadContextGoodies(httpChannel) {
//httpChannel must be the subject of http-on-modify-request QI'ed to nsiHTTPChannel as is done on line 8 "httpChannel = subject.QueryInterface(Ci.nsIHttpChannel);"
//start loadContext stuff
var loadContext;
try {
var interfaceRequestor = httpChannel.notificationCallbacks.QueryInterface(Ci.nsIInterfaceRequestor);
//var DOMWindow = interfaceRequestor.getInterface(Components.interfaces.nsIDOMWindow); //not to be done anymore because: https://developer.mozilla.org/en-US/docs/Updating_extensions_for_Firefox_3.5#Getting_a_load_context_from_a_request //instead do the loadContext stuff below
try {
loadContext = interfaceRequestor.getInterface(Ci.nsILoadContext);
} catch (ex) {
try {
loadContext = subject.loadGroup.notificationCallbacks.getInterface(Ci.nsILoadContext);
} catch (ex2) {}
}
} catch (ex0) {}
if (!loadContext) {
//no load context so dont do anything although you can run this, which is your old code
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var contentWindow = loadContext.associatedWindow;
if (!contentWindow) {
//this channel does not have a window, its probably loading a resource
//this probably means that its loading an ajax call or like a google ad thing
return null;
} else {
var aDOMWindow = contentWindow.top.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);
var gBrowser = aDOMWindow.gBrowser;
var aTab = gBrowser._getTabForContentWindow(contentWindow.top); //this is the clickable tab xul element, the one found in the tab strip of the firefox window, aTab.linkedBrowser is same as browser var above //can stylize tab like aTab.style.backgroundColor = 'blue'; //can stylize the tab like aTab.style.fontColor = 'red';
var browser = aTab.linkedBrowser; //this is the browser within the tab //this is where the example in the previous section ends
return {
aDOMWindow: aDOMWindow,
gBrowser: gBrowser,
aTab: aTab,
browser: browser,
contentWindow: contentWindow
};
}
}
//end loadContext stuff
}
i'm making a chrome extension that opens a web-site if the current tab is not the same web-site, so i managed to get all of the tabs like this:
chrome.tabs.getAllInWindow(null, allTabs);
and i wrote a function to display it:
function allTabs(tabs) {
var tabsURLS = '';
for (var i = 0; i < tabs.length; i++) {
tabsURLS = tabs[i].url + '\n';
}
alert(tabsURLS);
}
but i need to get the current page url so i get the current tab by this:
var object=chrome.tabs.getCurrent(function(){;});
but i cant get to page properties like id or url and this alert shows "undefined" ...
alert(object);
while this alert doesn't work at all
alert(object.id);
in the end, i read this page chrome.tabs and i was shocked when i read this line
getCurrent
chrome.tabs.getCurrent(function callback)
Gets the tab that this script call is being made from. May be undefined if called from a non-tab context (for example: a background page or popup view).
so i don't think that there is a solution of getting the current opened tab from chrome extension...
I believe that you need to use getSelected instead
<html>
<head>
<script>
chrome.tabs.getSelected(null, function(tab) {
var tabId = tab.id;
var tabUrl = tab.url;
alert(tabUrl);
});
</script>
</head>
the final code was like this, and it worked just fine.. :
var tabUrl;
chrome.browserAction.onClicked.addListener(function(activeTab) {
var x=activeTab.url;
var newURL = "https://www.google.com";
if (x!= newURL) {
//to open a page in a new tab
chrome.tabs.create({url: newURL,"selected":true});
//to open the page with the current tab
chrome.tabs.update(activeTab.id, {url:newURL});
}
});
The current accepted answer is out of date.
According to MDN, tabs.getSelected() is depricated
Use this instead:
tabs.query({active: true})
Ensure to set the correct permissions in manifest.json to access tab information:
"permissions": [
"tabs",
"http://*/*"
],
After that, you can determine the URL by using
chrome.tabs.getSelected(null, function (tab) {
alert(tab.url);
});