I'm opening a popup and want to have a click action in it cause the execution of some jQuery in the page that opened it. Everything I find online says I should be able to do that with window.opener, (e.g. JQuery - Write to opener window)
But when I console.log window.opener, it's just 'true', not a real object. window.opener.jQuery is undefined as is window.opener.$ and 'window.opener.document'.
Here's the window open code:
window.open('http://google.com' , "moderatorWindow", 'width=300, height=300');
This is in Safari. Other pages are able to launch a popup and when I inspect window.opener on those, I get a real object. What am I doing wrong?
Your variable is true and not an object because of same-domain policy rules. Just like an iframe, if the popup you open is not on the same domain or sub-domain then it is lost to you after you create it. The web would be a very unsecure place if I could say, open a (hidden) iframe on my site to gmail.com and was able to read your email.
Even if the popup is on a sub-domain you have to do extra work and set the document.domain value of both windows to the root domain (eg. mydomain.com). This is to ensure that the popped-up site wants to be known to its parent (again, think security, if my coke.ning.com community could open a hidden iframe to your pepsi.ning.com and do brute force attempts at a login, etc.)
To prove my point try actually going to google.com and opening up Firebug (or Inspector if you're using Safari or Chrome) and doing:
var bob = window.open('http://google.com' , "moderatorWindow", 'width=300, height=300');
bob.window.location.href; // returns "http://www.google.com/"
Lastly, feel free to call jQuery on the child page to modify elements on the same page and vice-versa but you can't use jQuery from one page to modify the dom of the other page. I tried this a few years ago to try to save on some loading time and, unless something has changed, it doesn't work. jQuery seems to be bound to the window object of where it was created. Weird things happen.
Presumably you are calling:
console.log(window.opener);
which should call the toString() method of whatever window.opener references. It should reference a window object, which is a host object. Per the ECMA-262, a host object's toString() method (if it has one) can return anthing it likes, even throw an error (try it on certain IE host objects implemented using ActiveX).
This article might help: http://developer.apple.com/library/safari/#documentation/AppleApplications/Conceptual/SafariJSProgTopics/Articles/Cross-documentmessaging.html
Related
Let's say I am currently at the following link:
"localhost/admin/test" when i do
window.open("/user/list/2034", "_blank")
it will appear like this:
localhost/admin/test/user/list/2034
what can i do to make it like this instead?
localhost/user/list/2034
I am assuming that windows should be window. If it really is windows then you have a custom object and need to show us what that is before we can answer your question.
The other point to note is that window.open will open a new window, regardless what you name it, so you don't need to use the _blank name. You only need to specify a name if you want to subsequently reuse that window (e.g. open another URL in the same other window).
When at http://localhost/admin/test, if you do:
window.open("/user/list/2034")
It will go to http://localhost/user/list/2034, unless...
window.open has been redefined somewhere. You can do console.log(window.open) and the console should say something like ƒ open() { [native code] } if it hasn't been redefined.
Your web server is responding to /user/list/2034 with a redirect to /admin/test/user/list/2034. The network tab in your developer console will show you the HTTP requests and responses where you can see if the web server is redirecting.
Your link really doesn't start with a / and you actually have window.open("user/list/2034")
You're viewing a cached version of the page with the above error in it, the source code is fixed but the browser hasn't loaded it. Try again in a private browsing window to see if it still happens.
You have some browser plug-in or extension interfering with your page. Try another browser/computer without the extensions and see if it still happens.
I am attempting to share data across subdomains using Safari. I would like to use an HTML5 database (specifically localStorage as my data is nothing but key-value pairs).
However, it seems as though data stored to example.com can not be accessed from sub.example.com (or vice versa). Is there any way to share a single database in this situation?
Update 2016
This library from Zendesk worked for me.
Sample:
Hub
// Config s.t. subdomains can get, but only the root domain can set and del
CrossStorageHub.init([
{origin: /\.example.com$/, allow: ['get']},
{origin: /:\/\/(www\.)?example.com$/, allow: ['get', 'set', 'del']}
]);
Note the $ for matching the end of the string. The regular expression in the above example will match origins such as valid.example.com, but not invalid.example.com.malicious.com.
Client
var storage = new CrossStorageClient('https://store.example.com/hub.html');
storage.onConnect().then(function() {
return storage.set('newKey', 'foobar');
}).then(function() {
return storage.get('existingKey', 'newKey');
}).then(function(res) {
console.log(res.length); // 2
}).catch(function(err) {
// Handle error
});
Check https://stackoverflow.com/a/39788742/5064633
There is simple way to use cross-domain anything, just create simple page that will be included as proxy iframe hosted on domain you try to access, send PostMessage to that iframe and inside iframe you do your LocalStorage database manipulation. Here is a link to article that do this with lcoalStorage. And here is demo that send message to different page in subdomain check the source code, it use iframe and PostMessage.
EDIT: New version of sysend.js library (used by above demo) use BroadcastChannel if browser support it, but still it require Iframe. Recent version also simplify using of Cross-Origin messages, you have html of the iframe in repo, that you can use (or you can use simple html file with single script tag with the lib) and in parent you just need to call one function sysend.proxy('https://example.com'); where example.com need to have proxy.html file (you can also use your own filename and different path).
Google Chrome blocks localStoage access from an iFrame in another domain by default,unless 3rd party cookie is enabled and so does Safari on iPhone...the only solution seems to be opening the parent domain on a different domain and then sending to to the Child via window.postMessage but looks ugly and shifty on phones...
Yes. This is how:
For sharing between subdomains of a given superdomain (e.g. foo.example.com vs bar.example.com vs example.com), there's a technique you can use in that situation. It can be applied to localStorage, IndexedDB, SharedWorker, BroadcastChannel, etc, all of which offer shared functionality between same-origin pages, but for some reason don't respect any modification to document.domain that would let them use the superdomain as their origin directly.
NOTE: This technique depends on setting document.domain to allow direct communication between iframes on different subdomains. That functionality has now been deprecated. (As of April 2021 it continues to work in all major browsers however. From Chrome v109 the feature will be disabled unless an Origin-Agent-Cluster: ?0 header is also sent.)
NOTE: Be aware that this technique removes the same-origin defences that block malicious script on a subdomain from affecting the main-domain window, or visa versa, potentially broadening the attack surface for XSS attacks. There are other security implications for shared hosting as well - see the MDN document.domain page for details.
(1) Pick one "main" domain to for the data to belong to: i.e. either https://foo.example.com or https://bar.example.com or https://example.com will hold your localStorage data. Let's say you pick https://example.com.
(2) Use localStorage normally for that chosen domain's pages.
(3) On all other https://*.example.com pages (the other domains), use JavaScript to set document.domain = "example.com"; (always the superdomain). Then also create a hidden <iframe>, and navigate it to some page on the chosen https://example.com domain (It doesn't matter what page, as long as you can insert a very little snippet of JavaScript on there. If you're creating the site, just make an empty page specifically for this purpose. If you're writing an extension or a Greasemonkey-style userscript and so don't have any control over pages on the example.com server, just pick the most lightweight page you can find and insert your script into it. Some kind of "not found" page would probably be fine).
(4) The script on the hidden iframe page need only (a) set document.domain = "example.com";, and (b) notify the parent window when this is done. After that, the parent window can access the iframe window and all its objects without restriction! So the minimal iframe page is something like:
<!doctype html>
<html>
<head>
<script>
document.domain = "example.com";
window.parent.iframeReady(); // function defined & called on parent window
</script>
</head>
<body></body>
</html>
If writing a userscript, you might not want to add externally-accessible functions such as iframeReady() to your unsafeWindow, so instead a better way to notify the main window userscript might be to use a custom event:
window.parent.dispatchEvent(new CustomEvent("iframeReady"));
Which you'd detect by adding a listener for the custom "iframeReady" event to your main page's window.
(NOTE: You need to set document.domain = example.com even if the iframe's domain is already example.com: Assigning a value to document.domain implicitly sets the origin's port to null, and both ports must match for the iframe and its parent to be considered same-origin. See the note here: https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy#Changing_origin)
(5) Once the hidden iframe has informed its parent window that it's ready, script in the parent window can just use iframe.contentWindow.localStorage, iframe.contentWindow.indexedDB, iframe.contentWindow.BroadcastChannel, iframe.contentWindow.SharedWorker instead of window.localStorage, window.indexedDB, etc. ...and all these objects will be scoped to the chosen https://example.com origin - so they'll have the this same shared origin for all of your pages!
The most awkward part of this technique is that you have to wait for the iframe to load before proceeding. So you can't just blithely start using localStorage in your DOMContentLoaded handler, for example. Also you might want to add some error handling to detect if the hidden iframe fails to load correctly.
Obviously, you should also make sure the hidden iframe is not removed or navigated during the lifetime of your page... OTOH I don't know what the result of that would be, but very likely bad things would happen.
And, a caveat: setting/changing document.domain can be blocked using the Feature-Policy header, in which case this technique will not be usable as described.
However, there is a significantly more-complicated generalization of this technique, that can't be blocked by Feature-Policy, and that also allows entirely unrelated domains to share data, communications, and shared workers (i.e. not just subdomains off a common superdomain). #jcubic already described it in their answer, namely:
The general idea is that, just as above, you create a hidden iframe to provide the correct origin for access; but instead of then just grabbing the iframe window's properties directly, you use script inside the iframe to do all of the work, and you communicate between the iframe and your main window only using postMessage() and addEventListener("message",...).
This works because postMessage() can be used even between different-origin Windows. But it's also significantly more complicated because you have to pass everything through some kind of messaging infrastructure that you create between the iframe and the main window, rather than just using the localStorage, IndexedDB, etc. APIs directly in your main window's code.
The code below works well. Here is my problem: The window url redirects, but the original url is not logged in my browser history.
For example, if I visit "http://example.com/page1", the browser redirects to "http://example.com/test", as it should. However, I need the original url visited ("http://example.com/page1") to show up in my browser history so that I can call upon it in a different function.
Is there anyway to get the original url visited to log in my browser's history before redirecting?
<!-- script to enable age verification cookies and ensure people have age checked -->
<script type="text/javascript">
$(document).ready(function(){
if (window.location =="http://example.com/home") {//do nothing
} else {
window.location = "http://example.com/test";
}
});
</script>
I think what you need is window.location.href. This adds the previous URL to the browser history.
I came across this behavior myself and it was because I was loading pages into chrome via the filesystem, i.e. using the file:// protocol. I started an HTTP server, and using that got it to keep the history.
tl;dr, just show me the code
var newUrl = "https://example.com.page2";
// Navigate to newUrl, adding a new entry to the Browser History
window.location.assign(newUrl);
window.open(newUrl, "_top");
JavaScript Browser Navigation With History
There are at least two methods to navigate (redirect) while retaining browser history. With Vanilla JavaScript, one of these are likely what we're looking for:
Easiest: window.location.assign() - part of the Location object in the Browser Window API.
Most Powerfull: window.open() - part of the Browser Window API. window.open() is far more powerful than location.assign() - as it can affect not just the current browser tab, but can also be used within an <iframe>, control which browsing context (a tab, window or iframe) to control, as well as change window features - including options such as the window's default size and position, whether to open a minimal popup window, and so forth.
Keep in mind that window.open() has caveats and usability/user experience issues, as it can open Popups - the exact same popups that most browsers block (Chrome, Firefox) because advertisers / spammers abuse(d) the functionality provided by window.open(). It's still a viable API to use, when used properly.
Browser History can also be managed and controlled directly via the Browser History API, including reading from, modifying existing, and adding new history entries. The History API however does not control navigation, and cannot be used for redirection. It's very often used with Single Page Applications, such as AngularJS, React, Vue.js, Svelte, etc.
Most of the text / descriptions below are directly sourced from MDN Web Docs. Please see the included links for more information. I have slightly modified the descriptions and examples from the MDN API Reference to be more relative to the question asked.
window.location.assign()
Source / Reference: https://developer.mozilla.org/en-US/docs/Web/API/Location/assign
The window.location.assign() method causes the window to load and display the document at the URL specified. After the navigation occurs, the user can navigate back to the page that called window.location.assign() by pressing the "back" button.
If the assignment can't happen because of a security violation, a DOMException of the SECURITY_ERROR type is thrown. This happens if the origin of the script calling the method is different from the origin of the page originally described by the Location object, mostly when the script is hosted on a different domain.
If the provided URL is not valid, a DOMException of the SYNTAX_ERROR type is thrown.
window.location.assign() Syntax
window.location.assign(url)
window.location.assign() Parameters
url: Is a string containing the URL of the page to navigate to.
window.location.assign() Example
var newUrl = "https://example.com.page2";
// Navigate to newUrl, adding a new entry to the Browser History
window.location.assign(newUrl);
window.open()
Source / Reference: https://developer.mozilla.org/en-US/docs/Web/API/Window/open.
⚠️ NOTE: I've only included a VERY small amount of information related to the extremely versitile window.open() method. I highly recommend you review the full documentation for window.open().
The open() method of the Window interface loads a specified resource into a new or existing browsing context (that is, tab, window, or <iframe>) under a specified name.
window.open() Syntax
open()
open(url)
open(url, target)
open(url, target, windowFeatures)
window.open() Parameters
url: Optional
A string indicating the URL or path of the resource to be loaded. If an empty string ("") is specified or this parameter is omitted, a blank page is opened into the targeted browsing context.
target: Optional
A string, without whitespace, specifying the name of the browsing context the resource is being loaded into. If the name doesn't identify an existing context, a new context is created and given the specified name. The special target keywords, _self, _blank, _parent, and _top, can also be used.
This name can be used as the target attribute of <a> or <form> elements.
windowFeatures: Optional
A string containing a comma-separated list of window features in the form name=value — or for boolean features, just name.
⚠️ NOTE: See the window.open() syntax for the full reference of Window Features.
window.open() Return value
A WindowProxy object. The returned reference can be used to access properties and methods of the new window as long as it complies with Same-origin policy security requirements.
window.open() Description
The Window interface's open() method takes a URL as a parameter, and loads the resource it identifies into a new or existing tab or window. The target parameter determines which window or tab to load the resource into, and the windowFeatures parameter can be used to control the size and position of a new window, and to open the new window as a popup with minimal UI features.
Note that remote URLs won't load immediately. When window.open() returns, the window always contains about:blank. The actual fetching of the URL is deferred and starts after the current script block finishes executing. The window creation and the loading of the referenced resource are done asynchronously.
window.open() Basic Example
For answering the question, the minimal form of window.open() to browse to a new URL, in the same browser tab, retaining browser navigation history.
var newUrl = "https://example.com/page2";
// Navigate to newUrl, adding a new entry to the Browser History
window.open(newUrl, "_top");
Here is the scenario:
I have a container page that swaps iFrames in and out to show different content. All iFrames come from the same domain. https is enabled.
The container page has an object called Flow, with functions set/getParameter
The first iFrame, s0-welcome, creates an object, data, and calls Flow.setParameter('data', data);
The container then replaces the first iFrame with a second iFrame, s1-transfer.
The s1-transfer calls Flow.getParameter('data') and stores it in a local variable s1data
In the IE9 debug tools console, if I type s1data it shows me all the properties of that object. However, if I call s1data.hasOwnProperty('prop1'), I get a "Can't execute code from a freed script" error. If I call Object.prototype.hasOwnProperty.call(s1data, "prop1"), everything works fine.
It looks to me that there can be 2 possibilities:
1) Container page holds on to the reference from the first iFrame, but when the first iFrame gets disposed, it loses some of the data. This seems unlikely since the only thing I can't access is functions
2) There is a security restriction that does not allow one iFrame to run code related to another iFrame even if both iFrames are from the same domain.
Any thoughts?
Just ran into a similar issue. For me, simply changing s1data.hasOwnProperty('prop1') into ('prop' in s1data) made the error go away.
In firefox I have opened a locally stored file with the file:// protocol
(file:///c:/temp/foo.html)
foo.html contains Java Script which (among others) is supposed a new
window without URL:
var new_window = window.open("","", "height=100,left=50,width=200");
When this line is reached, Firefox displays this "Firefox prevented this site from opening a pop-up window". I don't understand why Firefox gives this warning, obviously, the file (foo.html) is under my control (since it's stored locally and I have opened it with the file:// protocol, and, additionally, the window to be opened doesn't point to any file that could contain any sensitive data, as the url parameter in the open method is set to "".
But besides all this, it seems I can't even force or allow firefox to open the window anyway. There's this "options" button on the yellow "Firefox prev...." bar which supposedly should allow to create exceptions, yet I can't.
So, the question basically boils down to: how can I allow a local html file to open an empty window with Javascript within Firefox.
Thanks / Rene
This is a Firefox security precaution, see this link:
http://kb.mozillazine.org/Links_to_local_pages_don't_work
However, it looks like this extension will allow you to override it:
https://addons.mozilla.org/en-US/firefox/addon/281
This is the popup blocker, which block popups not opened by an explicit user action like a click.
You cannot force it to open the popup, you need to allow Firefox to open it.
I suggest you to test the new_window variable to see if it is null. In this case, display a message to the user so that he allows the domain to open popup windows.