setting up a webkit on an iframe before load - html

I am trying to mimic what wkwebview does on iOS to an iframe on a webclient.
Essentially what happens is before the iframe is loaded it injects a function the iOS client can read.
on the page loaded within the iframe it calls a function to communicate with the iOS client.
if (window.webkit) {
window.webkit.messageHandlers.interOp.postMessage(chatMsg);
} else if (window.parent) {
window.parent.postMessage(chatMsg, '*');
}
I don't want it to fall into the else window.parent block since postMessage gets quite a bit of traffic from extensions and other applications.
I'd like to add to the Iframe's window object the same webkit.messageHandlers.interOp.postMessage function and listen on that level.
The Iframe domain and the WebClient domain are different.
Another approach would be to only listen to calls to postMessage called by the Iframe. Any ideas are welcome thanks.

If it is a same-domain iframe, then you simply assign a function to the window of the parent, as in:
window.iframeMessageReceiver = msg => alert(`Message received from iframe: ${msg}`)
And you call this function inside of your iframe's if block:
parent.iframeMessageReceiver(chatMsg)

Related

requestFullscreen works no more in message event handler

User clicks a button and in click event handler we postMessage to iframe. Iframe handles it in message event handler and calls element.requestFullscreen(). In older browsers it worked (eg. in Chrome 65) but in current (72) it errors with Failed to execute 'requestFullscreen' on 'Element': API can only be initiated by a user gesture..
Is there a way to transfer "gesture initiated" flag in postMessage call?
Note that iframe has allow="fullscreen" attribute.
As always with iframes, it depends on here it is hosted relative to the parent document.
If you are running a same-origin document in that frame, then you can simply call requestFullScreen directly on the element you wish form the main doc:
const frameDoc = frame.contentDocument;
frameDoc.getElementById('el-to-fs').requestFullscreen(); // assuming polyfill
jsfiddle Since StackSnippetsĀ® overly protected iframes won't allow access nor fullscreen.
But if you were, you wouldn't have had this issue in Chrome (you'd still have had in FF).
Because even though it is true that this method requires an user-gesture, postMessage being fast enough, you are able to use it with a same-origin frame in Chrome.
What happens in this browser is that a cross-origin document must have received an user-gesture before being able to call requestFullscreen.
Once the cross-origin frame has been marked as interacted-by-the-user, then you'll be able to call requestFullscreen even from main-doc's events: jsfiddle (still, only in Chrome).
But, for a cross-browser solution, you'd have to
load this content as same-origin (e.g using a proxy)
or to use a small hack where you set the <iframe> in fullscreen mode and let the inner document know you did so, so it can style its document accordingly: jsfiddle
main.js
onclick = e => {
frame.contentWindow.postMessage("you're going fullscreen", '*');
frame.requestFullscreen();
};
frame.js
onmessage = e => {
if(message.data === "you're going fullscreen") {
// trigger our special fullscreen CSS
document.documentElement.classList.add('fullscreen');
// do some DOM cleaning if needed
}
else if(message.data === "you're exiting fullscreen") {
document.documentElement.classList.remove('fullscreen');
}
};

Chrome extension: loading a hidden page (without iframe)

Is there a way to load a page, hidden from the user?
I can't use an iframe in a background page, because the page has frame-busting techniques.
I can't use an XHR, because the page has AJAX - I need its (dynamically generated) DOM.
I'm afraid that you don't have any other option than inserting the iframe anyway. To bust the iframe buster, you can employ the following techniques:
If the iframe is blocked by the X-Frames-Option: DENY, just remove the header using the webRequest API - see Getting around X-Frame-Options DENY in a Chrome extension?.
If the frame buster uses something like
if (top !== self) {
top.location.href = location.href;
}
Then block the scripted navigation by set the sandbox attribute on the iframe:
var frame = document.createElement('iframe');
frame.sandbox = 'allow-scripts';
frame.src = 'data:text/html,<script>' +
'if (top !== self) { top.location.href = location.href;}' +
'alert(" (runs the rest of the code) ");' +
'</script>';
document.body.appendChild(frame);
Navigation will be blocked without throwing any errors. The following message is logged to the console though:
Unsafe JavaScript attempt to initiate navigation for frame with URL '(...URL of top page...)' from frame with URL '(....URL of frame..)'. The frame attempting navigation of the top-level window is sandboxed, but the 'allow-top-navigation' flag is not set.
These methods will always work, unless:
The page contains <meta http-equiv="X-Frame-Options" content="deny">.
The frame busting script is implemented as if (top === self) { /* run code*/ }
In these cases, you have no other option than opening a new tab, read its content, then close it. See chrome.tabs.create and chrome.tabs.remove.
You can use popUnder s to load data:
var win2;
function loadPopUnder(){
win2 = window.open("about:blank","",
width=150,height=150,scrollbars=0,resizable=0,toolbar=0,location=0,menubar=0,status=0,directories=0");
win2.blur();
window.focus()
}
win2.document.location.href='http://www.exampe.com/url';
Actually they may open in a new tab in certain circumstances - you have to check the actual behavior.
Also it is an advantage that this one is a browser independent solution.

Actionscript works when tested in flash, but not on html page?

I am trying to create an ad for a website. When someone clicks on the ad, it is supposed to redirect them to a website, and register the click with google analytics.
I have done this with the following script:
import flash.external.ExternalInterface;
movieClip_3.addEventListener(MouseEvent.CLICK, onClick);
function onClick(event:MouseEvent):void {
trace("hi");
ExternalInterface.call("console.log", "test");
//ExternalInterface.call("_gaq._trackPageview", "/vpv/annoncer/[firmanavn.dk]");
navigateToURL(new URLRequest("http://www.google.com"), "_blank");
}
When i run this using preview->flash and i click on the surface, (where there is a big red square called movieClip_3) It opens the webpage. However when i try to publish as html, the big red square shows, but nothing happens on click. Not even console.log. I have tried setting allowscriptaccess = always but that does not change anything.
Can you guys help me? Any help is appreciated.
Security problems?
Developers should validate all URLs before passing them to this
function.
For local content running in a browser, calls to the navigateToURL()
method that specify a "javascript:" pseudo-protocol (via a URLRequest
object passed as the first parameter) are only permitted if the SWF
file and the containing web page (if there is one) are in the
local-trusted security sandbox. Some browsers do not support using the
javascript protocol with the navigateToURL() method. Instead, consider
using the call() method of the ExternalInterface API to invoke
JavaScript methods within the enclosing HTML page.
source: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/net/package.html#navigateToURL()
EDIT:
Since javascript is not permitted out of the sandbox, you can try with ExternalInterface:
ExternalInterface.call("javascript_functionname", "mypage.html");
In the parameters for publishing:
'allowScriptAccess', 'always',
You can only test this on your server not locally.
I'd suggest double checking the security settings (right click on flash container->Global Settings-> Advanced -> Trusted Location Settings). Also make sure your html file contains the javascript function you're trying to execute and look for blocked pop-up notifications in the browser. Maybe you just don't allow pop-ups to run.

How do I access the popup page DOM from bg page in Chrome extension?

In Google Chrome's extension developer section, it says
The HTML pages inside an extension
have complete access to each other's
DOMs, and they can invoke functions on
each other. ... The popup's contents
are a web page defined by an HTML file
(popup.html). The popup doesn't need
to duplicate code that's in the
background page (background.html)
because the popup can invoke functions
on the background page
I've loaded and tested jQuery, and can access DOM elements in background.html with jQuery, but I cannot figure out how to get access to DOM elements in popup.html from background.html.
can you discuss why you would want to do that? A background page is a page that lives forever for the life time of your extension. While the popup page only lives when you click on the popup.
In my opinion, it should be refactored the other way around, your popup should request something from the background page. You just do this in the popup to access the background page:
chrome.extension.getBackgroundPage()
But if you insist, you can use simple communication with extension pages with sendRequest() and onRequest. Perhaps you can use chrome.extension.getViews
I understand why you want to do this as I have run into the problem myself.
The easiest thing I could think of was using Google's method of a callback - the sendRequest and onRequest methods work as well, but I find them to be clunky and less straightforward.
Popup.js
chrome.extension.getBackgroundPage().doMethod(function(params)
{
// Work with modified params
// Use local variables
});
Background.html
function doMethod(callback)
{
if(callback)
{
// Create/modify params if needed
var params;
// Invoke the callback
callback(params);
}
}
As other answers mention, you can call background.js functions from popup.js like so:
var _background = chrome.extension.getBackgroundPage();
_background.backgroundJsFunction();
But to access popup.js or popup.html from background.js, you're supposed to use the messages architecture like so:
// in background.js
chrome.runtime.sendMessage( { property: value } );
// in popup.js
chrome.runtime.onMessage.addListener(handleBackgroundMessages);
function handleBackgroundMessages(message)
{
if (message.property === value)
// do stuff
}
However, it seems that you can synchronously access popup.js from background.js, just like you can synchronously access the other way around. chrome.extension.getViews can get you the popup window object, and you can use that to call functions, access variables, and access the DOM.
var _popup = chrome.extension.getViews( { type: 'popup' } )[0];
_popup.popupJsFunction();
_popup.document.getElementById('element');
_popup.document.title = 'poop'
Note that getViews() will return [] if the popup is not open, so you have to handle that.
I'm not sure why no one else mentioned this. Perhaps there's some pitfalls or bad practices to this that I've overlooked? But in my limited testing in my own extension, it seems to work.

Prevent webpage from scrolling when scrolling inside a Flash object

I'm sure this must be a common question, but I haven't found an answer elsewhere.
I've got a Flash object embedded in a long webpage. I listen for the MOUSE_WHEEL event in Flash, and scroll my Flash content accordingly. However, when I scroll over the Flash object, the webpage also scrolls.
Is there any way to prevent this behaviour, i.e. lock the webpage's scrolling position when the Flash object has focus? I'd prefer not to have to use JavaScript.
Here is an excellent solution that doesn't require JavaScript:
http://www.spikything.com/blog/index.php/2009/11/27/stop-simultaneous-flash-browser-scrolling/
(Technically, it DOES use JavaScript, but the JavaScript is injected by Flash, so you don't need to add anything to the HTML page yourself. In other words, the only code you need to manage is AS3).
This seems to work on every browser I've tested.
I don not think this is possible without JavaScript.
You would need to communicate from the Flash movie to the browser using ExternalInterface whenever the Flash movie changes focus.
Then, have a JavaScript function on the page trap and eat the mousewheel event:
if (window.addEventListener)
/** DOMMouseScroll is for mozilla. */
window.addEventListener('DOMMouseScroll', handleWheelEvent, false);
/** IE/Opera. */
window.onmousewheel = document.onmousewheel = handleWheelEvent;
function handleWheelEvent(e){
e.preventDefault();
}