0

I'm currently trying to copy a div to another browser tab with the events still working.

I found ways to do this on the same tab, but not for a different one, for example:

https://api.jquery.com/clone/

jQuery: clone elements AND events

Here's my approach:

var newWindow;

if (navigator.userAgent.match(/msie|trident/i))
{
  newWindow = window.open("", "_blank");
}
else
{
  newWindow = window.open("about:blank", "_blank");
}

var currentDate = moment().format(L11n.get(".dateTimeFormat"));

var printDate = L11n.get(".printDate") + " " + currentDate;
var cssUrl = $app.appRoot + "rt/main.css";
var jsUrl = $app.appRoot + "app/main.js";
var d3Url = $app.appRoot + "pub/d3.js";
var title = L11n.get(".contractDetail");
var start = "<!DOCTYPE html> \
  <html xmlns=\"http://www.w3.org/1999/xhtml\" style=\"height: 100%;\"> \
  <head id=\"Head1\"> \
  <title>" + title + "<\/title> \
  <link href=\"" + cssUrl + "\" rel=\"stylesheet\" type=\"text/css\" /> \
  <script src=\"" + jsUrl + "\" language=\"javascript\" type=\"text/javascript\"></script> \
  <script src=\"" + d3Url + "\" language=\"javascript\" type=\"text/javascript\"></script> \
  <script src=\"pub/jquery.js\" language=\"javascript\" type=\"text/javascript\" /></script> \
  <body class=\"detailTabsView limitWidthPrint\" style=\"margin-bottom: 0; margin-top: 0; height: auto;\"> \
  <div class =\"detailPrintHeader\">" + printDate + "</div>\
  <div class =\"detailContainer\">";
var end = "<\/div><\/body><\/html>";

newWindow.document.write(start + detailHtmlString + end);
newWindow.document.close();

//newWindow.document.$("#dashboardFrame").replaceWith($(".ALL #dashboardFrame").clone(true));
var dash = $(".ALL #dashboardFrame").clone(true, true);

$(newWindow).load(function ()
{
  console.log("loaded");
  $(newWindow.document.body).find("#dashboardFrame").replaceWith(dash);
});

$(newWindow.document).ready(function ()
{
  console.log("ready");
});

newWindow.focus();

The interesting part is this:

var dash = $(".ALL #dashboardFrame").clone(true, true);

$(newWindow).load(function ()
{
  console.log("loaded");
  $(newWindow.document.body).find("#dashboardFrame").replaceWith(dash);
});

Further explanation:

I have a webapp that, for example, shows a diagram made with D3 (Data-driven-documents). It also shows other information, split up into a tab pane. That diagram has some datapoints that show a tooltip when the user hovers over them.

The app also has a button that opens the current tab in a new window. The tooltips don't work on that new window, but it would be nice if they would.

Edit:

Simple example:

Tab A = source tab, with a button in it that has a click-event bound to it. The event reads, let's say the current time and writes it to an alert box.

Then I open a new tab with javascript, let's call it Tab B. When Tab B is loaded, I want to append the button from Tab A to the body of Tab B. The event on the button still has to work in Tab B.

Community
  • 1
  • 1
Hopfeeyy
  • 7
  • 1
  • 6

1 Answers1

3

TL:DR:

You can only solve this by re-binding the events on the new tab in the ready event

I tried that with this piece of code. You have to pass the event-handler within that piece of code (sry for the long-line-example). Just copy that snipped into your dev-console, paste and run it. You will get an alert();

var newWindow = window.open('about:blank', '_blank');
newWindow.document.write('<!doctype html><html><head><title>Test</title><script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script><script type="text/javascript">$(document).ready(function() { $(window).load(function(e) { alert(\'onload\'); }); });</script><script type="text/javascript">function onload() {alert("load");}</script></head><body><div>Test</div></body></html>');
newWindow.document.close();

You can't get the event from another tab. That's browser restriction. You can use an iFrame for that.


Edit: As I said you can use an iFrame to retrieve the loaded message. But it also should be possible within a new tab. There is a window.postMessage method in HTML5. You can see which browsers are supportet on caniuse.com. You may also have a very brief look at David Walsh's site. He explains how to use it.

I do not have ressources right now. But you can simple "google" it. Or test it otherwise within your developer console to access a variable declared in windowA on windowB. The result will be undefined


Edit part 2: I don't think it is possible without having a script-ressource or a inline JavaScript in the DOM.

See example:

<!doctype html>
<html>
    <head>
        <title>Test</title>
        <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                $('#test_button').bind('click', function (e) {
                    alert('Button was clicked!');
                    e.preventDefault();
                });

                $(window).load(function (e) {
                    var body = '<!doctype html><html><head><title>Test2</title><scr' + 'ipt type=\'text/javascript\' src=\'https://code.jquery.com/jquery-2.1.4.min.js\'></scr' + 'ipt></head><body id="body">' + $('#test_button').clone(true, true).attr({'id': 'test2_button', 'data-time': new Date()}).wrap("<div />").parent().html() + '</body></html>';
                    console.log(body);
                    var newWindow = window.open('about:blank', '_blank');
                    newWindow.document.write(body);
                    //newWindow.document.write('<!doctype html><html><head><title>Test2</title><scr' + 'ipt type=\'text/javascript\' src=\'https://code.jquery.com/jquery-2.1.4.min.js\'></scr' + 'ipt></head><body>' +  + '</body></html>');
                    newWindow.document.close();
                });
            });
        </script>
    <body>
        <div id="test">
            <button id="test_button">Test-Button</button>
        </div>
    </body>
</html>

I just copy the #test_button into the new window. As a new window is opened a new DOM is generated without the JavaScript event (bind) of the #test_button.

If you append the JavaScript for event-handling you can of course copy your hole content into a new tab/window. Just move your event-bindings into a JavaScript file and append it like I did with the jQuery-file.

Furthermore you just can open the new tab programmatically within your existing tab as you can't access the other tabs ressource (DOM).

You can pass a parameter as well if you like. Just add a param to the open. See other SO-question.

If it helped to clearify your question please feel free to mark this one as answer.


Edit 3

I hope I got it right this time! Try this one:

JavaScript-file (e. g. test.js)

$(document).ready(function () {
    console.log('ready');
    $('#test_button').bind('click', function (e) {
        alert('Button was clicked!');
        e.preventDefault();
    });
})

HTML-file

<!doctype html>
<html>
    <head>
        <title>Test</title>
        <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
        <script type="text/javascript" src="test.js"></script>
        <script type="text/javascript">
            $(document).ready(function () {
                $(window).load(function (e) {
                    var body = '<!doctype html><html><head><title>Test2</title><scr' + 'ipt type=\'text/javascript\' src=\'https://code.jquery.com/jquery-2.1.4.min.js\'></scr' + 'ipt><scr' + 'ipt type=\'text/javascript\' src=\'test.js\'></scr' + 'ipt></head><body id="body">' + $('#test_button').clone(true, true).attr({'data-time': new Date()}).wrap("<div />").parent().html() + '</body></html>';
                    console.log(body);
                    var newWindow = window.open('about:blank', '_blank');
                    newWindow.document.write(body);
                    //newWindow.document.write('<!doctype html><html><head><title>Test2</title><scr' + 'ipt type=\'text/javascript\' src=\'https://code.jquery.com/jquery-2.1.4.min.js\'></scr' + 'ipt></head><body>' +  + '</body></html>');
                    newWindow.document.close();
                });
            });
        </script>
    <body>
        <div id="test">
            <button id="test_button">Test-Button</button>
        </div>
    </body>
</html>
Community
  • 1
  • 1
webprogrammer
  • 792
  • 15
  • 26
  • Ok so you're saying that is impossible to copy a div with its' events to another browser tab. That's what I was fearing :(. Do you have a source for this browser restriction argument? – Hopfeeyy Aug 10 '15 at 13:31
  • @Hopfeeyy please see the updated answer. It really depends on what you want to achieve. As I understand you want to retrieve a information as the new tab was loaded, am I right? – webprogrammer Aug 10 '15 at 13:55
  • No, I think you mean something different than me. I want to copy an element from a browser tab to a new browser tab, with the events bound to the element that gets copied still working in the new tab. Simple example: Tab A = source tab, with a button in it that has a click-event bound to it. The event reads, let's say the current time and writes it to an alert box. Then I open a new tab with javascript, let's call it Tab B. When Tab B is loaded, I want to append the button from Tab A to the body of Tab B. The event on the button still has to work. I do not want to retrieve any messages. – Hopfeeyy Aug 10 '15 at 14:09
  • @Hopfeeyy please see again my edit 2. As far as I know it isn't possible. You can try the example. If you share a JavaScript ressource for multiple tabs it is possible. Lets say Tab A uses `main.js` with event-bindings and tab B also uses `main.js` with same bindings. – webprogrammer Aug 10 '15 at 14:59
  • Did you even read the code I posted in the question? I'm doing exactly the same as you described anyways. Did you test your answer? Does it work for you? – Hopfeeyy Aug 11 '15 at 06:01
  • @Hopfeeyy, as I already said, it isn't possible if you do it in another tab. If you do it on the same tab it will work. If you call your tab programmatically - like you do - then you can give your button a `data-attribute`. E. g. `$('#test_button').clone(true, true).attr({'id': 'test2_button', 'data-time': new Date()}).wrap("
    ").parent().html()` your `load` event still won't fire von tab A if tab B is loaded... Please update your question with detailled information so I can fix that for you.
    – webprogrammer Aug 11 '15 at 06:21
  • I'm afraid you don't exactly get what I want :(. Anyways, in your code sample in the comment, you do a `clone(true,true)`, but at the end you do `.html()`, so the events are lost again. Right? – Hopfeeyy Aug 11 '15 at 06:52
  • @Hopfeeyy You're totally right. You can't copy your events to the other HTML-Doc. In my example I have the `bind` on the `button-click` for test purposes. On the same document it will work. But not for copying into another as DOM-events get lost. As I said: If you transfer that event into a single JS-File you can use it on both sides with same events. I think it's the way you should go. – webprogrammer Aug 11 '15 at 07:07
  • The events are in the same file, it's called main.js and linked in the header section of Tab A and Tab B (as you can see in the code). But I guess that's not important, cause you said the events get lost when I copy them to another document. How would the element in the other document know that it should 'use' events from the js-file? They're not bound to it anymore. So I guess it really is impossible to do what I want. Thanks for the help though! If you update your answer to "This is not possible" or something similar, I can mark it as answer. – Hopfeeyy Aug 11 '15 at 07:18
  • @Hopfeeyy please see my last updated answer :) I hope I can clearify what I mean. Click event gets fired on first tab as also on second tab. You also can use a class instead of an id if you prefer that one. Hope this helps :) – webprogrammer Aug 11 '15 at 07:33
  • Ok I see what you do. You are copying the html text without events to the new tab, and on the new tab you re-bind the event. That will be alot of work to do for my application, but I guess that's a success, because now I know more than before and have a way to go :). Please update your answer again with "You can only solve this by re-binding the events on the new tab in the ready event. Thanks a lot! :) – Hopfeeyy Aug 11 '15 at 07:49
  • @Hopfeeyy no problem! I updated my answer and would be appreciated if you mark it as solved :) thank you! – webprogrammer Aug 11 '15 at 08:19