Move IFRAME DOM to new window - javascript

Despite is it not useful to move an IFRAME to a newly opened window (see similiar questions, the IFRAME will reload), one can move the IFRAMEs content, eg. the top HTML node to another window. Eg.
iframe_html_node=document.getElementById('my_iframe').contentDocument.firstChild;
new_window=window.open();
new_window.document.replaceChild(iframe_html_node,new_window.document.firstChild);
Of course, one can also replace deeper levels of the DOM if only parts are needed.
However, there is one show stopper: As the new window is opened blank, it has no valid document.location set, so there is no base URI for it's contents links and ressources, which will in turn all go blank (tested in Chrome), eg. CSS and images are broken.
One can of course set new_window.document.location to the IFRAMEs one before copying, but this triggers a lot of mess if included JS frameworks attach their handlers and so on. Also it implies an race condition where we have to be cautionous about the time we replace the HTML node, as it may be overwritten by the loading document.
Any suggestions?

Related

In Chrome DevTools extension, how to retrieve selected node from multi-frame page for extension elements sidebar pane

I'm developing a Chrome devtools extension that displays content in an elements sidebar pane based on the currently selected node. As described in the documentation, the mechanism for working with the selected node is calling chrome.devtools.inspectedWindow.eval, with the eval'd code including $0, the variable pointing to the most recently selected node. For example, to display the currently selected node in the console, I could call eval('console.log($0)'). For background on this issue, see this stackoverflow question.
The problem I have concerns pages containing iframes. The eval call takes an options object with a frameURL property. For example:
eval('console.log($0)',{frameURL: 'http://www.iframeexample.com'}).
This allows the caller to evaluate the code in a specific frame. However, each frame (except about:blank srcs) has its own $0 variable pointing to the most recently selected node in that frame's window. If a page has five frames, there are five different values for $0, one for each frame. When my extension receives the onSelectionChanged event, how can I know which node the user has currently selected in the devtools elements panel, i.e. which frame's window $0 points to correct node? How can I possibly provide content for the correct node?
My second related problem involves iframes with similar sources. For example, the page frames.com has two iframe elements with the same src (excluding differences in the src hash value). A call to eval with the duplicate src value will execute in one of the frames, but not the other. I can find no way to check both frames for the currently selected node, $0. In this case, if the user selects a node in the frame that I cannot access via an eval call, there is no way to serve content related to that node.
Providing content or functionality related to the currently selected node is the key use case for adding a devtools extension element sidebar panel. The onSelectionChanged event fires when the extension should check for a new selection, but the event callback receives no information on the selected node. Given the problems described above, it seems impossible to reliably locate the user's node selection on multi-frame pages. Am I missing something fundamental in my approach?

Check what part of JavaScript code is rendering a specific Html element?

On this page https://detail.1688.com/offer/548835845261.html
I want to scrape shipping price and shipping weight as highlighted in image.
I dont know how is this being loaded into DOM.
Its not included in DOM. Its not even loaded by an AJAX call.
Not sure whats going on.
The only relevent part I see on initial page source is
data-unit-config="{"calculationUrl":"https://laputa.1688.com/offer/ajax/CalculateFreight.do","freightTemplateId":"10342228","beginAmount":"1","unitWeight":"1","refPrice":"88.00","isCodOffer":""}"
I tried making GET request to that URL
https://laputa.1688.com/offer/ajax/CalculateFreight.do?freightTemplateId=10342228&beginAmount=1&unitWeight=1&refPrice&88.00&isCodOffer
but not luck.
I want to ask is there any way I can check what part of JavaScript code is rendering a specific Html element?
My recommendation would be:
When the element appears, inspect it.
In the Elements panel, find the first ancestor element to the mystery element that has no mysterious origins (an element that you know how it is getting on the page).
Right-click the ancestor element from step #2 and navigate and select Break on... ==> Subtree modification
Refresh the page _with the devtools on the Elements panel (seems to not work otherwise)
Now anytime JavaScript modifies descendants of the element you set the breakpoint on, the sources panel will pause and allow you to inspect what is going on.

Move elements to iframe's parent with data and events

this is the situation.
I have a complex UI inside an iframe in which a user can perform several actions before submitting. During the process, the user can switch to another page (in the iframe) and come back. That means 2 postbacks inside the iframe.
Obviously, I don't want the user to lose everything but since all the actions have been done on the client-side, I can't reload the previous state from the server.
So now, I'm trying to move the first page content to the iframe parent and put it back in place when we come back. I'm half way there since the elements show back in the page but they lose their data attributes and event handlers.
I'm using this to move the content on the parent :
$("#resp").clone(true).attr("id", "refillResp").appendTo(window.top.$("#global"));
And this to put it back :
window.top.$("#global").find("#refillResp").clone(true).attr("id", "resp").appendTo($("#tdResp"));
Is there anyone who knows a way to do this ?
PS: I've tested how the content react when simply moved on the parent and data and events are already gone.
It is more a comment, but it does not fit in there.
Moving DOM element around different documents around is alway a little bit risky. Because it could lead to unexpected behavior (memory leaks, elements that behave strange). In current browsers it most of the time works, but i would not recommend it.
If you use jQuery you have another problem. jQuery has a cache for storing informations about data and event that are assigned to an Object, this cache is stored with the documents window. For further details please read this answer, to another question:
How to set jQuery data() on an iFrame body tag and retrieve it from inside the iFrame?
So if you move element with jQuery between different document, you will currently on the one hand loose these informations, on the other hand it could result in memory leaks.
With events it is even more complicate. e.g. if you have delegated events it could be become completely messy.
If you need to exchange data between iframe and parent you should think of some other logic.
I also mention this in a comment to the other answer of me, where i referred to this post:
How to set jQuery data() on an iFrame body tag and retrieve it from inside the iFrame?

Remove all jQuery event handlers

I am creating a jQuery Mobile web app, which loads some pages.
For example, a.html is my main page. It may call b1.html,b2.html,...,b100.html (User may click on one of buttons). (The pages are loading with ajax navigation feature of jQuery Mobile)
And there is some events in each b[i].html page, and ids and many things are same in every b[i].html page. But the point is, at any time, just one of them may be in DOM. So there will be no id conflicts or such.
The problem
The problem is the conflict of the events. When user come back to a.html from b[i].html, the HTML will be removed, but events will remain. This will cause many problems if I first go to b[i].html, and then come back to a.html and then go to b[j].html. I mean, b[j].html will not work correctly... :(
What I have tried
I have putted this in a.html, to remove all events:
$("#mainpage").off("pagebeforeshow").on("pagebeforeshow",function() {
$("*").not("#mainpage").off();
//Other initialization codes...
});
But, problem not solved...
(mainpage is the id of data-role="page" of a.html)
Example
For example, I have this in each b[i].html:
$(window).resize(function () {
alert("Resized");
});
At the beginning (in a.html), If I resize the window, there will be no alerts, but after visiting b[i].html and then coming back to a.html, I'll see alerts if I resize the window, even with that line of code (What I have tried part.)...
So, How to remove those event handlers when users come back to a.html from b[i].html?
If you are using jQuery Mobile, more than one of said pages may exist in the dom at the same time, resulting in non-unique id conflicts.
I would ditch putting js on the individual pages and have it done from the primary page, or through a script loading system such as require.js. Then do all of the events through delegation from the document. Obviously that won't work with window.resize(), but it doesn't need to be delegated anyway.
"Can you please explain more?"
Basically, if you are including scripts on the child pages, you will need to have both setup and teardown for every page. setup adds the events, and teardown removes them. If you instead used a single global script that adds ALL of the events using event delegation from the document, all of the pages should work. Obviously that global script could get pretty big on a complex site, so you could instead use require.js to load in js that does the same thing as needed, preventing it from loading the same dependency more than once.
As far as removing all events, I've never tried this, but can you use $("*").off()? According to the docs it should work. I'm not sure how it will affect jQuery mobile. To remove events on the document and/or window, you will have to do it manually because $("*") will not select them.
$(document).on("vmousemove","#link",func) is how you delegate an event from the document.

How can we a get a tab element when the document is known?

Before explaining the question, I want to explain my main goal (If there is a better way than my approach):
I have the document element available with me and ideally I wanted to get a browser element such that it identifies a tab uniquely. In my previous approach I used
gBrowser.getBrowserForDocument(doc);
This returned the browser which was indeed unique to the tab (in the sense that attributes stored in it persisted across pages).
If instead, I don't store the browser element, and after moving to another page in the same tab I try the above command again, then the browser is no longer the same one as before (in the sense that it has lost all the stored attributes).
Therein lies my main problem. I want to get hold of the tab browser which I am able to refer to using different documents loaded in the same tab.
I read about a similar function:
gBrowser.getBrowserForTab(tab);
I have a feeling this might work. But again, I am not able to understand where I can get the parameter "tab" from (given a document).
Note: I am using GWT for the development of the extension
EDIT: To clarify the intent of the question, here's the use case as well as my approach:
In my extension, I am interested in monitoring user behaviour on particular websites. In a way it can be thought of as a session which remains active until the user stays on the same website. During the session, I am often required to store various attributes specific to user behaviour. One of the attributes concerning the question in "isSessionActive":"Y" or "" (blank string stands for no)
To make the code more optimal, I do not instantiate a browser for all the tabs in the beginning. Instead, I wait for the cue using an onLoad function. : if a relevant website is visited
Once that happens, I make a call to get the browser using the current document element, see if it has a non empty value for the attribute isSessionActive. If it does not, I set the attributes value to "Y" and instantiate my class which handles the profiling after that.
If it has value "Y", I know that the session is still active and that I don't need to initialize.
The problem which I'm facing is that after the first instantiation, when I move to another page within the same tab, I expected that the call to
gBrowser.getBrowserforDocument(doc);
would get me the browser instantiated previously since it is basically the same tab.
This is not happening. Each time I get a new Browser instance which does not have the attribute isSessionActive as "Y" (probably because the new page has a new document element). Thus, at present all my code instantiates over and over again which is what I do not want.
If you're only working with the current tab (and not any background tabs), then you could just use gBrowser.selectedTab https://developer.mozilla.org/en/XUL/tabbrowser#p-selectedTab

Categories