I've got a popup window that gives data back to its parent. Using window.opener.document.data = data_from_popup;
This work well in FF, but in IE (6/7) the data can be accessed for the time the popup is still displayed. When I close the popup it looks like the data gets garbage collected.
I've tried to use a clone() function for the data received from the popup :
window.opener.add_data(data_from_popup);
and in the parent :
function add_data(data_from_popup) {
data = clone(data_from_popup);
}
It somewhat works, but in certain conditions the clone() function seems to recurse infinitely.
Have you ever experienced the same thing, and is there a way to prevent that without using a clone function?
Not sure exactly what you are experiencing, but I have successfully stored data on the opener from the child popup on a regular basis in IE (6,7 & 8) in development and production applications.
do you have a URL or some more source code that you can provide?
on a related note... you aren't trying to determine the type of an object on the opener... from the popup are you? - there's some known IE bugs in this area.
Update:
Here's a quick example...
<!--main window-->
<script>
function getThing(id){
url = 'http://mysite.com/...whatever...';
features = 'locationbar=X,menubar=Y...';
window['popup4'+id] = open(url, 'someNameWithoutSpaces', features);
}
function popupCallback(data){
alert('I got data back! ' + data);
document.getElementById('someID').innerHTML = '<b>' + data.label + ' (' + data.id + ')</b>';
//close the popup (now that we have/are done with the data)
window['popup4someID'].close();
}
</script>
<div id="someID">{Nothing Selected Yet}</div>
<input type="button" value="Pick One" onclick="getThing('someID');"/>
<!--popup window-->
<script>
function saveSelection(){
//acquire data however you want/need
var selData = {};
selData.id = 123456;
selData.label = 'iPod Touch (Jeff Atwood Edition)';
//call callback on opener
window.opener.popupCallback(selData);
}
</script>
Update 2
In testing it appears that in IE7,IE8 (but not IE6) after the popup window is closed, any reference data is lost (the references don't capture a snapshot) thus if you need the data after the popup is closed, you will need to clone it.
I thought if the data can be wrapped in an Array, cloning is a piece of cake. Just call .slice() on it to copy it, but... that doesn't work either!
I guess you'll need to save the values out that you need (either to form elements, or the DOM) since IE doesn't look like it will let you use them after the popup closes. :-(
The way I finally did it is by json encoding the complex object I wanted to pass to the parent in the popup window. The data passed back is then a simple string and can be copied without problem. On the parent side the json encoded string is evaluated to a Javascript object.
Related
I currently only know javascript. But the thing is I looked up how to do it and some people talk about something called localStorage. I have tried this and for some reason when I jump to a new page those variables aren't kept. Maybe I am doing something wrong? I jump to a new page via
and all I want do do is select a certain image. take that image to a new page and add it to that page.
I tried using the localStorage variables and even turning it into JSON.stringify and doing JSON.parse when trying to call the localstorage to another script. It didn't seem to work for me. Is there another solution?
This is some of my code. There are two scripts.
document.querySelectorAll(".card").forEach(item => {
item.addEventListener("click", onProductClick);
})
var div;
var productImg;
var ratingElement;
var reviewCount;
var price;
function onProductClick(){
// This took a week to find out (this.id)
// console.log(this.id);
div = document.getElementById(this.id);
productImg = div.getElementsByTagName('img')[0];
ratingElement = div.getElementsByTagName('a')[2];
reviewCount = div.getElementsByTagName('a')[3]
price = div.getElementsByTagName('a')[4];
console.log(div.getElementsByTagName('a')[4]);
var productData = [div, productImg,ratingElement,reviewCount,price];
window.localStorage.setItem("price", JSON.stringify(price));
}
function TranslateProduct(){
console.log("Hello");
}
This is script 2
var productPageImage = document.getElementById("product-image");
var myData = localStorage['productdata-local'];
var value =JSON.parse(window.localStorage.getItem('price'));
console.log(value);
// function setProductPage(img){
// if(productImg != null){
// return;
// }
// console.log(window.price);
// }
To explain my thought process on this code in the first script I have multiple images that have event listeners for a click. I wanted to Click any given image and grab all the data about it and the product. Then I wanted to move that to another script (script 2) and add it to a dynamic second page. yet I print my variables and they work on the first script and somehow don't on the second. This is my code. in the meantime I will look into cookies Thank you!
Have you tried Cookies
You can always use cookies, but you may run into their limitations. These days, cookies are not the best choice, even though they have the ability to preserve data even longer than the current window session.
or you can make a GET request to the other page by attaching your serialized object to the URL as follows:
http://www.app.com/second.xyz?MyObject=SerializedData
That other page can then easily parse its URL and deserialize data using JavaScript.
you can check this answer for more details Pass javascript object from one page to other
Below is my code.
It is resulting in unexpected behaviour.
It navigates to bing.com but it does not fill in the text field. Also, I have noticed that the console get cleared after navigating to a new webpage.
window.location = "https://www.bing.com";
window.onload = function(){
var editSearch = document.getElementById("sb_form_q");
editSearch.value = "Quux";
}
You are binding the onload function to the existing window object.
When the browser loads the new page, it will make a new window object which won't have your property set on it.
JavaScript run in one page (even when you are running it through developer tools) can't persist variables onto a different page.
(Storage mechanisms like localStorage and cookies are available, but you would need code in the subsequent page to look for them).
JavaScript is only valid for the current page you are on. When you are executing code from DevTools console, you are executing code on that page itself. So, when you navigate to another page using window.location you loose the onload handler you have defined.
To add handlers to a different page, it must be connected to your page (the parent) in some way, like an iframe or a popup.
ifrm = document.getElementById('frame');
ifrm.src = 'http://example.com';
ifrm.contentWindow.onload = function () {
// do something here with
// ifrm.contentWindow.document.getElementById('form')
}
As #Quentin said.
But you can do another way like ..
var keyword = "Quux";
window.location = "https://www.bing.com/search?q="+keyword;
I am working on a web based application, in which I have to open popup window. I am using window.open() method to open the popup, like this:
window.open(url, "popupWin");
where url contains the URL I would like my popup window to navigate to. Now, the problem is, if I execute window.open() from multiple tabs (with same or different URLs), at least on Chrome, it might / might not give you the same window which was opened earlier. This behaviour is inconsistent, I mean, either it should get me fresh window every time, or it should get me previously opened window every time.
I need to persist the same popup window for entire domain. How can I do that?
Well looks like there is a direction to go or at least to give it a try.
It fully remains on localStorage which gives you ability to share the knowledge across your tabs within a single domain.
The code I give below does not work yet (it is only a direction), so don't expect too much from running it as it is.
What it does: it saves the popups by the url in a localStorage and when you try to open a new one with the same url it won't do that. If you don't want to distinguish them by URL it is even simpler: store boolean in a localStorage instead of an object.
What it does not do but should:
it should listen to the popup onunload (close) event and reset the localStorage information accordingly. Best for you here is just to set your localStorage boolean value to false
it should listen to the current tab onunload (reload, close) event and also reset something according to Your logic. As I understand the best for you would be just check whether this tab is the last one from your domain (you can also do this using localStorage, e.g. on every new tab adding its identifier, e.g. creation timestamp and destroying it on tab close) and if it is set your localStorage boolean value to false.
This, I think, would be enough to solve the problem. And finally a small piece of code:
// get the localstorage url map
function getOpenPopups() {
var obj = localStorage.getItem('mypopups');
return obj ? JSON.parse(obj) : {};
}
// set the localstorage url map
function setOpenPopups(object) {
localStorage.setItem('mypopups', JSON.stringify(object))
}
// open the popup
function popup(url, title) {
var popups = getOpenPopups();
// check whether popup with this url is already open
// if not then set it and open the popup
if (!popups[url]) {
popups[url] = true;
setOpenPopups(popups);
return window.open('abc', 'cde');
}
else {
return false;
}
}
jsFiddle
From w3c documentation we can see that window.open() returns a reference to the newly created window, or null if the call failed. That means we can keep it in memory and check for closed flag of that window.
var newWindow = window.open('/some/path', 'TestWindow');
// ...
if (!newWindow.closed) {
}
Keep in mind that if window with following name exists, page will be loaded in the same window without opening new one.
Other variants of name parameter like _blank, _self, _top, _parent you can find in official docs too.
I wrote a script that's running from ebay listing iframe. It's working fine, it runs on $(document).ready(), sends an AJAX request to a remote server, gets some info, manipulate the DOM on 'success' callback, everything working perfect...
However, I added a piece of code, which should get the document.referrer, and extract some keywords from it, if they exist. Specifically, if a user searches ebay for a product, and clicks on my product from the results, the function extracts the keywords he entered.
Now, the problem is, that function is not running on page load at all. It seems like it blocks the script when it comes to that part. This is the function:
function getKeywords(){
var index = window.parent.document.referrer.indexOf('_nkw');
if (index >= 0){
var currentIndex = index + 5;
var keywords = '';
while (window.parent.document.referrer[currentIndex] !== '&'){
keywords += window.parent.document.referrer[currentIndex++];
}
keywords = keywords.split('+');
return keywords;
}
}
And I tried calling two logs right after it:
console.log('referrer: ' + window.parent.document.referrer);
console.log(getKeywords());
None of them is working. It's like when it comes to that 'window.parent.document.referrer' part, it stops completely.
But, when I put this all in a console, and run it, it works perfectly. It logs the right referrer, and the right keywords.
Does anybody know what might be the issue here?
The reason it is working on the console is because your window object is the outer window reference and not your iframe. Besides that, on the console:
window.parent === window
// ==> true
So, on in fact you are running window.document.referrer and not your frame's window.parent.document.referrer.
If you want to access your frame's window object you should something like
var myFrame = document.getElementsByClassName('my-frame-class')[0];
myFrame.contentWindow === window
// ==> false
myFrame.contentWindow.parent.window === window
// ==> true
This might help you debug your problem, but I guess the browser is just preventing an inner iframe from accessing the parent's window object.
I've done my research and struggled with this for a while, but I need your help.
I'm building a Chrome DevTools extension. It should should pass the currently selected element from the 'Elements' panel as a reference to a JS object defined in a content script.
It is important that I pass the reference to the selected element, or some other way of identifying the element from the content script.
I understand the workflow with 'isolated worlds' in Chrome DevTools. I also understand messaging between extension pages, background page and content scripts. This only happens with JSON primitives, hence no JS scope passing.
How can I pass the element selected in devtools Elements panel to the content script that lives in the inspected page?
Edit
Here's what I know so far:
Getting a reference to the selected element:
chrome.devtools.inspectedWindow.eval("(" + function(){ console.log($0) }.toString() + ")()")
That function expression will run in the context of the inspected page, not in the context of the devtools extension and not in the context of the 'isolated world' of the content script. I don't believe it is possible to pass in a reference to a different context using closures.
The reference to the selected DOM element $0 can't be returned because it can't be serialized to JSON due to circular references.
The chrome.devtools namespace isn't available outside the devtools extension page. The $0 reference can't be used outside the evaluated expression in chrome.devtools.inspectedWindow
Workaround
As a workaround, I chose to use the shared DOM to mark the selected element with a data attribute and use that to re-select it in the context of the content script. Messaging is used to pass the data attribute marker around.
Here's a simplified version of the code:
In the devtools extension page:
// setup a communication port
port = chrome.runtime.connect({name: "devtools"});
chrome.devtools.panels.elements.onSelectionChanged.addListener(function(){
// expression to run in the context of the inspected page
var expression = "(" + mark.toString() + ")()"
// evaluate the expression and handle the result
chrome.devtools.inspectedWindow.eval(expression, dispatchToContentScript)
});
function mark(){
// mark the currently selected element
$0.setAttribute('data-selected')
// send the marker to the callback
return { marker: 'data-selected' }
}
function dispatchToContentScript(data){
// dispatch data to the content script which is listening to the same port.
port.postMessage(data)
}
In the content script:
var port = chrome.runtime.connect({name: "devtools"});
port.onMessage.addListener(function(data) {
// re-select the element in the context of the content script
var el = document.querySelector('['+ data.marker +']')
})
It's not a clean solution but I can use it for my needs.
Is there a simpler way to achieve the same result - identify from a content script the element selected in the devtools 'Elements' panel?
The API for chrome.devtools.inspectedWindow has been updated to support executing scripts in the context of the content script.
This update in the official Chrome API obsoletes our hacks described above. We can now achieve the expected result with:
chrome.devtools.inspectedWindow.eval("aContentScriptFunction($0)",
{ useContentScriptContext: true });
The $0 parameter will reference the element selected in the Elements panel.
my way of doing it is sort of a hack too..
instead of injecting a content script defined in your extention you can inject a script tag pointing to your files online (or locally, relative to inspected html ):
//devtools.js
var str = "var s = document.createElement('script');" +
"s.src = 'http://extentionDomain/extentionFile.js';" +
"document.body.appendChild(s);";
chrome.devtools.inspectedWindow.eval(str);
online file defines a global:
var myExtention = { doStuff: function(selectedElement){ ..}}
and devtools can call it and pass it the selected element:
chrome.devtools.panels.elements.onSelectionChanged.addListener(function(){
chrome.devtools.inspectedWindow.eval('myExtention.doStuff($0)');});
however i have not found a way to send a reference back from the inspected window to the devtools extention with this setup.