I need to make a parent iFrame on domain A go fullscreen from its postMessage event handler which gets triggered by a postMessage from the window in domain B. I have the postMessage communication setup perfectly. The "allowfullscreen" attribute is set on the iframe too. But the requestFullScreen() method seems to silently quit. After searching I found that due to security reasons, requestFullScreen works only on event handlers for events like mouse clicks,
keypress etc. I tried forcefully executing a click on the iFrame using jquery click() and it comes into the click handler too but the requestFullScreen doesn't work. I tried clicking on the iFrame directly and it goes fullscreen.
How do I make this work?
Here's my code - for the parent on domainA.
I have made sure that the post message handler is executed when my child on domain B posts a message
<!DOCTYPE HTML>
<html>
<script type="text/javascript" src="jquery.js"></script>
<script>
var container;
$(function(){
container = $('#parentFrame')[0];
container.addEventListener("click",goFullScreen);
window.addEventListener("message", receiveMessage, false);
});
function receiveMessage(event)
{
/* Use this code to restrict request from only one particular domain & Port!
Port not needed in this case*/
if (event.origin !== "http://myChildDomain.com")
{
return;
}
/*Retrieving relevant variables*/
var message=event.data;
var source=event.source;
var origin=event.origin;
//Forcefully generating a click event because fullscreen won't work when directly requested!
container.click();
}
goFullScreen = function (){
if (container.mozRequestFullScreen) {
// This is how to go into fullscren mode in Firefox
// Note the "moz" prefix, which is short for Mozilla.
container.mozRequestFullScreen();
} else if (container.webkitRequestFullScreen) {
// This is how to go into fullscreen mode in Chrome and Safari
// Both of those browsers are based on the Webkit project, hence the same prefix.
container.webkitRequestFullScreen();
}
}
</script>
<body>
<iframe id="parentFrame" src="http://myChildDomain/child.html" width="804" height="600" frameborder="0" scrolling="no" allowfullscreen style="border: 5px solid #00ff00">
</iframe>
</body>
</html>
Related
This seems to be the easiest thing to do, but it's just not working. In a normal browser the .html and .js files works perfectly, but in the Chrome/Firefox extension the onClick function is not performing what it's supposed to do.
.js file:
function hellYeah(text) {
document.getElementById("text-holder").innerHTML = text;
}
.html file:
<!doctype html>
<html>
<head>
<title>
Getting Started Extension's Popup
</title>
<script src="popup.js"></script>
</head>
<body>
<div id="text-holder">
ha
</div>
<br />
<a onClick=hellYeah("xxx")>
hyhy
</a>
</body>
</html>
So basically once the user clicks "hyhy", "ha" should change into "xxx". And again - it works perfectly in the browser but does not work in the extension. Do you know why? Just in case I'm attaching the manifest.json below as well.
manifest.json:
{
"name": "My First Extension",
"version": "1.0",
"manifest_version": 2,
"description": "The first extension that I made.",
"browser_action": {
"default_icon": "icon.png",
"default_popup": "popup.html"
},
"permissions": [
"http://api.flickr.com/"
]
}
Chrome Extensions don't allow you to have inline JavaScript (documentation).
The same goes for Firefox WebExtensions (documentation).
You are going to have to do something similar to this:
Assign an ID to the link (<a onClick=hellYeah("xxx")> becomes <a id="link">), and use addEventListener to bind the event. Put the following in your popup.js file:
document.addEventListener('DOMContentLoaded', function() {
var link = document.getElementById('link');
// onClick's logic below:
link.addEventListener('click', function() {
hellYeah('xxx');
});
});
popup.js should be loaded as a separate script file:
<script src="popup.js"></script>
Reason
This does not work, because Chrome forbids any kind of inline code in extensions via Content Security Policy.
Inline JavaScript will not be executed. This restriction bans both inline <script> blocks and inline event handlers (e.g. <button onclick="...">).
How to detect
If this is indeed the problem, Chrome would produce the following error in the console:
Refused to execute inline script because it violates the following Content Security Policy directive: "script-src 'self' chrome-extension-resource:". Either the 'unsafe-inline' keyword, a hash ('sha256-...'), or a nonce ('nonce-...') is required to enable inline execution.
To access a popup's JavaScript console (which is useful for debug in general), right-click your extension's button and select "Inspect popup" from the context menu.
More information on debugging a popup is available here.
How to fix
One needs to remove all inline JavaScript. There is a guide in Chrome documentation.
Suppose the original looks like:
<a onclick="handler()">Click this</a> <!-- Bad -->
One needs to remove the onclick attribute and give the element a unique id:
<a id="click-this">Click this</a> <!-- Fixed -->
And then attach the listener from a script (which must be in a .js file, suppose popup.js):
// Pure JS:
document.addEventListener('DOMContentLoaded', function() {
document.getElementById("click-this").addEventListener("click", handler);
});
// The handler also must go in a .js file
function handler() {
/* ... */
}
Note the wrapping in a DOMContentLoaded event. This ensures that the element exists at the time of execution. Now add the script tag, for instance in the <head> of the document:
<script src="popup.js"></script>
Alternative if you're using jQuery:
// jQuery
$(document).ready(function() {
$("#click-this").click(handler);
});
Relaxing the policy
Q: The error mentions ways to allow inline code. I don't want to / can't change my code, how do I enable inline scripts?
A: Despite what the error says, you cannot enable inline script:
There is no mechanism for relaxing the restriction against executing inline JavaScript. In particular, setting a script policy that includes 'unsafe-inline' will have no effect.
Update: Since Chrome 46, it's possible to whitelist specific inline code blocks:
As of Chrome 46, inline scripts can be whitelisted by specifying the base64-encoded hash of the source code in the policy. This hash must be prefixed by the used hash algorithm (sha256, sha384 or sha512). See Hash usage for <script> elements for an example.
However, I do not readily see a reason to use this, and it will not enable inline attributes like onclick="code".
I had the same problem, and didnĀ“t want to rewrite the code, so I wrote a function to modify the code and create the inline declarated events:
function compile(qSel){
var matches = [];
var match = null;
var c = 0;
var html = $(qSel).html();
var pattern = /(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/mg;
while (match = pattern.exec(html)) {
var arr = [];
for (i in match) {
if (!isNaN(i)) {
arr.push(match[i]);
}
}
matches.push(arr);
}
var items_with_events = [];
var compiledHtml = html;
for ( var i in matches ){
var item_with_event = {
custom_id : "my_app_identifier_"+i,
code : matches[i][5],
on : matches[i][3],
};
items_with_events.push(item_with_event);
compiledHtml = compiledHtml.replace(/(<(.*?)on([a-zA-Z]+)\s*=\s*('|")(.*)('|")(.*?))(>)/m, "<$2 custom_id='"+item_with_event.custom_id+"' $7 $8");
}
$(qSel).html(compiledHtml);
for ( var i in items_with_events ){
$("[custom_id='"+items_with_events[i].custom_id+"']").bind(items_with_events[i].on, function(){
eval(items_with_events[i].code);
});
}
}
$(document).ready(function(){
compile('#content');
})
This should remove all inline events from the selected node, and recreate them with jquery instead.
I decide to publish my example that I used in my case. I tried to replace content in div using a script. My problem was that Chrome did not recognized / did not run that script.
In more detail What I wanted to do: To click on a link, and that link to "read" an external html file, that it will be loaded in a div section.
I found out that by placing the script before the DIV with ID that
was called, the script did not work.
If the script was in another DIV, also it does not work
The script must be coded using document.addEventListener('DOMContentLoaded', function() as it was told
<body>
<a id=id_page href ="#loving" onclick="load_services()"> loving </a>
<script>
// This script MUST BE under the "ID" that is calling
// Do not transfer it to a differ DIV than the caller "ID"
document.getElementById("id_page").addEventListener("click", function(){
document.getElementById("mainbody").innerHTML = '<object data="Services.html" class="loving_css_edit"; ></object>'; });
</script>
</body>
<div id="mainbody" class="main_body">
"here is loaded the external html file when the loving link will
be clicked. "
</div>
As already mentioned, Chrome Extensions don't allow to have inline JavaScript due to security reasons so you can try this workaround as well.
HTML file
<!doctype html>
<html>
<head>
<title>
Getting Started Extension's Popup
</title>
<script src="popup.js"></script>
</head>
<body>
<div id="text-holder">ha</div><br />
<a class="clickableBtn">
hyhy
</a>
</body>
</html>
<!doctype html>
popup.js
window.onclick = function(event) {
var target = event.target ;
if(target.matches('.clickableBtn')) {
var clickedEle = document.activeElement.id ;
var ele = document.getElementById(clickedEle);
alert(ele.text);
}
}
Or if you are having a Jquery file included then
window.onclick = function(event) {
var target = event.target ;
if(target.matches('.clickableBtn')) {
alert($(target).text());
}
}
With HTML5, is there any way in IE11/Edge to populate a sandboxed iframe (<iframe sandbox></iframe>) with HTML other than using a src url? I am looking for a solution like srcdoc which works with all other modern browsers.
Using src with a data URI is not an option according to Microsoft as it "cannot be used [to] populate frame or iframe elements." Surprisingly, this does works for me in Edge but only for data URIs with less than 4096 characters.
All other options that I have found, e.g. in Alternatives to iframe srcdoc? and Html code as IFRAME source rather than a URL do not work for a sandboxed iframe.
Assuming usage of <iframe sandbox="allow-scripts"> is desired or acceptable, a possible workaround would be using window.postMessage() with the following setup:
index.html:
<!doctype html>
<html>
<body>
<iframe onload="connectIframe()" sandbox="allow-scripts" src="iframeConnect.html" name="srcdocloader"></iframe>
<script>
var SRCDOC_HTML = '<html><body><script src="https://code.jquery.com/jquery-3.2.1.js"><\/script><script>console.log("loaded srcdoc and dependencies", jQuery);<\/script><h1>done!</h1></body></html>';
var loaded;
function connectIframe (event) {
if (!loaded) {
loaded = true;
window.frames.srcdocloader.postMessage(SRCDOC_HTML, '*');
} else {
onloadSrcdoc();
}
}
function onloadSrcdoc () {
// ...
}
</script>
</body>
</html>
iframeConnect.html:
<!doctype html>
<script>
window.addEventListener("message", handler);
function handler(event) {
if (event.source === window.parent) {
window.removeEventListener("message", handler);
document.write(event.data);
document.close();
}
}
</script>
Note that the iframe's onload event will be triggered two times. The second time will be after the srcdoc html and all its dependencies got loaded.
I include the YouTube player as follows in my php file but the player does not show the fullscreen button. Switching to the flash player works (whether through changing the url from /embed to /v or by disabling &html5=1). What am I doing wrong?
An example is available here: http://jonnyrimkus.square7.ch/stuff/youtube_html5_fullscreen.php
<script>
var tag = document.createElement(\'script\');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName(\'script\')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubeIframeAPIReady() {
player = new YT.Player(\'player\', {
playerVars: {
\'allowfullscreen\': \'true\',
\'allowscriptaccess\': \'always\'
},
events: {
\'onReady\': onYouTubePlayerReady,
\'onStateChange\': playerStateChange,
\'onError\': playerStateError
}
});
}
</script>
<iframe id="player" width="425" height="356" border="0" frameborder="0" src="http://www.youtube.com/embed/36XdO9Iv9ew?enablejsapi=1&playerapiid=lastfmplayer&autoplay=1&html5=1&fs=1&origin=http://jonnyrimkus.square7.ch"></iframe>
The fullscreen button will also not be visible if the Youtube player is inside another iframe that does not have allowfullscreen attribute.
Unlike what Google's documentation says(as of 11/2014), the fs attribute in querystring does not seem to influence the visibility of fullscreen. The visibility seems to be influenced by allowfullscreen attribute in iframe which youtube player puts by default during instantiation. That said, if your embed the player inside another iframe you should also mark that iframe for allowfullscreen ( or all its variants webkitallowfullscreen mozallowfullscreen)
<iframe src='' frameborder='0' webkitallowfullscreen mozallowfullscreen allowfullscreen>
<!-- YT player-->
</iframe>
The way you are using the iframe api now does nothing, the api is made to bind on an empty element, like <div id="player"></div>, the id is the first argument in the new YT.Player function.
In order to load a youtube video with the iframe api you need this in the body:
<div id="player"></div>
<script type="text/javascript">
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
height: 480,
width: 640,
videoId: "36XdO9Iv9ew",
});
}
</script>
There is no need to explicitely specify you want to enable fullscreen when using the iframe api.
You can also just use the iframe without the api, you'll need to specify you want fullscreen when you use it.
<iframe width="640" height="480" frameborder="0" id="player" allowfullscreen="1" title="YouTube video player" src="http://www.youtube.com/embed/36XdO9Iv9ew?enablejsapi=1"></iframe>
Just using the iframe tag is a bit faster, but if you want to use the extra features of the iframe api you have no choice.
A page with examples (also check the source): http://qnet.co/yt
You can also implement the fullscreen feature yourself (not needed for Youtube, but still cool):
var goFullscreen = function(id) {
var el = document.getElementById(id);
if (el.requestFullScreen) {
el.requestFullScreen();
} else if (el.mozRequestFullScreen) {
el.mozRequestFullScreen();
} else if (el.webkitRequestFullScreen) {
el.webkitRequestFullScreen();
}
}
var leaveFullscreen = function() {
if (document.cancelFullScreen) {
document.cancelFullScreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.webkitCancelFullScreen) {
document.webkitCancelFullScreen();
}
}
and to make the Youtube player go fullscreen with: goFullscreen('player'), and leave fullscreen with: leaveFullscreen()
The different versions of requestFullscreen and cancelFullscreen are for different browsers, because the standard is not yet completely finished
More info on Javascript Fullscreen: http://johndyer.name/native-fullscreen-javascript-api-plus-jquery-plugin/ (relative old document, but still valid)
off-topic: It is useless to echo such a string with php, you can just paste it in the body the file outside of the php tags.
This is still an issue in July 2014, and you just wonder if Google will ever fix this. Actually you can force the Flash player in another way at the client end by using a UA Spoofer, and for Google Chrome browser for instance, Chrome Web Store - djflhoibgkdhkhhcedjiklpkjnoahfmg and then spoof a browser that doesn't understand HTML5.
Actually HTML5 video is still a disaster, and the grainey spikey-jaggy edges to the video and the herringbone patterning though faint is still distracting. Whereas Flash is Smooth, Flawless, Reliable, and Sharp edges with zero patterning artifacts.
HTML5 - still big thumbs down, I wouldn't inflict it on users.
Oh yes and still Fullscreen not appear in embeds like this
Rick Astley - Never Gonna Give You Up # viewpure embed
http://viewpure.com/dQw4w9WgXcQ
You can use the above example to fiddle and diddle with different browser plugins.
I have a html page.
html page has a iframe.
when I submit the form inside iframe, returned result is displayed inside that iframe.
How to display that result in parent of iframe??
<script type="text/javascript">
$(document).ready(function () {
$("#test").load(function (e) {
var htmlFromServer = $(e.target).contents().find("html").html();
});
});
</script>
<iframe id="test" src="HTMLPage1.htm"></iframe>
All you need to do is handle the onload event of the iframe. This event is triggered when the iframe receives response from the server.
I have built a jquery html5 canvas sketching app that accepts mouse events for desktop (pen tablets just use mouse events). I would also like to allow drawing with the finger on iphone, ipad, andriod devices as a mobile web enabled app. Since mobile devices also trigger mouse click events on their own: Does this mean that I should detect the type of browser and replace all mouse bindings with touch bindings in order to prevent events from double firing?
Here is a stupid example:
<!DOCTYPE html>
<html>
<head>
<script src="jquery.min.js"></script>
</head>
<body>
<canvas id="myCanvas" width="1600px" height="1600px" style="border:1px dashed gray;background-color:white;">
</canvas>
<script>
function brushStart() {
$('#myCanvas').css('background-color','blue');
}
function brushEnd() {
$('#myCanvas').css('background-color','red');
}
function brushMove() {
$('#myCanvas').css('background-color','yellow');
}
$('#myCanvas').bind('mousedown', brushStart);
$('#myCanvas').bind('mouseup', brushEnd);
$('#myCanvas').bind('mousemove', brushMove);
$('#myCanvas')[0].addEventListener('touchstart',brushStart,false);
$('#myCanvas')[0].addEventListener('touchend',brushEnd,false);
$('#myCanvas')[0].addEventListener('touchmove',brushMove,false);
</script>
</body>
</html>
I've used the following to do what you're looking for:
$("#myCanvas").bind("touchstart mousedown", function (event) {
var e = event.originalEvent;
e.preventDefault();
startX = (e.targetTouches != undefined) ? e.targetTouches[0].screenX : e.offsetX;
startY = (e.targetTouches != undefined) ? e.targetTouches[0].screenY : e.offsetY;
});
A couple of points -- you need to access the originalEvent in jQuery in order to work with targetTouches. Also, as I'm sure is apparent, you can substitute any property pair you need for offsetX/Y for the mouse events.