2012-05-08 18 views
9

Mam dwa okna, jeden jest otwarty od drugiego, więc mam właściwość opener w oknie "potomnym".Nie można przekazać funkcji z jednego okna do drugiego w IE

Okno nadrzędne ma jakąś funkcję w zasięgu globalnym, która musi być wywołana z funkcją jako pierwszy argument (będzie używana jako wywołanie zwrotne).

Obie strony są otwarte od tej samej domeny, więc nie mam żadnych same ograniczenia zasad pochodzenia (mam taką nadzieję) ...

w oknie dziecko mam kod jak ten

if(window.opener) { 
    window.opener.myFunction(function() { ... }); 
} 

Wszystko działa dobrze, dopóki nie spróbuję uruchomić go w IE. W tej przeglądarce argument, otrzymany przez myFunction, jest ZAWSZE typu Object (sprawdzany z typeof). Kodeks myFunction jest coś takiego:

window.myFunction = function(cb) { 
    alert('Callback type is ' + (typeof cb)); 
    if(typeof cb == 'function') 
     cb(); 
    else 
     alert('Not a function!'); 
} 

żywo demo: http://elifantiev.ru/ie-opener-issue/first.html

pytania jest:

  1. Czy to Standarts zachowanie zgodne?
  2. jest jakieś obejście tego problemu?
+0

Proszę podać wersje oprogramowania IE, w których występuje ten problem. –

+0

IE7 + (IE 7,8,9) – Olegas

Odpowiedz

6

Mimo że typeof zwraca "obiekt", funkcja nadal działa zgodnie z oczekiwaniami. Wywołanie funkcji cb() spowoduje wykonanie tej funkcji.

Alternatywą korzystania typeof celu ustalenia, czy parametr jest funkcja testowania dla właściwości połączenia, które oczekiwanej wszystkie funkcje są posiadać:

if (cb && cb.call) { cb(); } 

Jeśli przekazując do czegoś, co oczekuje funkcją go może być zawijany w ten sposób:

function newCb() { 
    return cb.apply(object, arguments); 
} 

Pamiętaj również, że przekazując funkcję od rodzica do dziecka, również typof jest również obiektem. Porównywanie oryginalnej funkcji z funkcją-jako-obiektem (po podróży w obie strony) zwraca wartość true. Jest to ważne, jeśli z jakiegoś powodu potrzebujesz odniesienia do pierwotnej funkcji (na przykład po anulowaniu subskrypcji).

+0

+1 dla 'if (cb && cb.call)' ... najlepiej trzymać z dala od 'typeof' –

+0

Opakowanie jest ładne, ale nie może być używane, ponieważ 'I trzeba dodać owijanie do dowolnej funkcji architektury, która może odbierać funkcję jako argument ... – Olegas

+0

Nie lubię ich, ale możesz prototypować funkcję, więc nie musisz się martwić o przepisanie całego frameworku, tylko twój klient po drugiej stronie. Za minutę zaktualizuję odpowiedź. – Jeff

2

Wygląda na to, że jest to zgodne z projektem.

http://www.kilometer0.com/blog/code/internet-explorer-ie-cross-window-javascript-object-typeof-bug/

https://bugzilla.mozilla.org/show_bug.cgi?id=475038

Ponieważ każde okno może mieć różne łańcuchy prototypowe funkcje nie mogą być przekazywane zgodnie z oczekiwaniami.Spróbuj zrobić coś takiego, aby potwierdzić:

var popup = window.open('second.html'); 

    window.myFunction = function(cb) { 
      alert(cb instanceof Function);  //false 
      alert(cb instanceof popup.Function); //true 
    } 

Więc oto jak to zrobić właściwego walidacji funkcji, jeśli były liczne funkcje martwić po stronie dominującej (nienawidzę prototyp, ale tym razem myślę, że utkniesz) :

nadrzędna Okno:

<html> 
<script type="text/javascript"> 
    /* give all our functions the validation check at once */ 
    Function.prototype.remote = function(cb) { 
     if(cb instanceof popup.Function) { 
      this(cb); 
     } else { 
      alert('Not a function!'); 
     } 
    }; 

    var popup, 
    myFunction = function(cb) { 
     cb(); 
    }, 
    test = function(cb) { 
     cb(); 
    } 

</script> 
<body> 
    <a href="#" onclick="popup = window.open('second.html'); return false;">Open window</a> 
</body> 
</html> 

Okno dziecka:

<html> 
<body> 
    <script type="text/javascript"> 
     var Parent = window.opener; 
     if(Parent) { 
      Parent.myFunction.remote(function(){ 
       alert('callback!'); 
      }); 

      Parent.test.remote(function() { 
       alert('callback again'); 
      }); 
     } 
    </script> 
    This is a second page! 
</body> 
</html> 

A oto przykład roboczych: http://dl.dropbox.com/u/169857/first.html

-1

Po otwarciu okna dziecko, można przypisać funkcję utworzoną przez rodzica w jego kontekście window. Można zobaczyć następujący kod uruchomiony w jsFiddle:

<html> 
<head> 
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script> 
<script> 

// will be called by the child window 
function MyExportedCallback(x) { 
    $("#my-callback-result").text("this callback was run with '" + x + "'."); 
} 

// will open a child window and create content for testing 
function MyLinkHandler() { 
    var wnd = window.open("about:blank"); 

    // IMPORTANT: this is where the parent defined function is "registered" 
    // into child window scope 
    wnd["myExternal"] = MyExportedCallback; 

    // auxiliary code to generate some HTML to test the external function 
    var put = function(x) { wnd.document.write(x); }; 
    put("<html><body>"); 
    put("<a href='#' onclick='window.myExternal(123);'>"); 
    put("click me to run external function"); 
    put("</a>"); 
    put("</body></html>"); 
} 

// attach events 
$.ready(function() { 
    $("#my-link").click(MyLinkHandler); 
}); 

</script> 
<body> 
<p><a id="my-link" href="#">Open window</a></p> 
<p id="my-callback-result">waitting callback...</p> 
</body> 
</html> 
+0

Głównym problemem jest przekazanie funkcji utworzonej w oknie potomnym jako argumentu do funkcji okna rodzica. – Olegas

+0

@Olegas, twój oryginalny post mówi: "Okno rodzica ma jakąś funkcję w zasięgu globalnym, które musi być wywołane z funkcją jako pierwszy argument (będzie używane jako wywołanie zwrotne)." Tak więc oczekiwałem, że problem wywoła funkcję zdefiniowaną w oknie nadrzędnym z okna podrzędnego. Przekazywanie funkcji w JavaScript, w sprawach praktycznych, jest jak przekazywanie jakiegokolwiek innego argumentu, i dlatego nie odkryłem go. Ale nie martw się, wygląda na to, że już rozwiązałeś swój problem, że nie potrzebujesz dalszej pomocy. –

+0

Aby zadzwonić - nie jest problemem. Przekazanie funkcji - jest problemem. W IE zmienia on 'typeof' na' Object' po przejściu przez granicę okna. – Olegas

2

Nawet jeśli można uzyskać to do pracy na razie nie liczyłbym na zdolność do dwóch okien przeglądarki, aby bezpośrednio wywoływać funkcje na siebie na około dużo dłużej. Istnieje zbyt wiele problemów związanych z bezpieczeństwem, nawet jeśli usuniesz problemy z wielu domen ze scenariusza.

Jedynym sposobem na zapewnienie bezpieczeństwa w przyszłości i zapewnienie, że działa we wszystkich przeglądarkach, jest użycie cross-document messaging APIs, które są obsługiwane we wszystkich nowoczesnych przeglądarkach, w tym w IE8 i wyżej.

Najbardziej szczegółowym przykładem, jaki mogłem znaleźć, gdy potrzebowałem rozwiązać ten problem, był ten window.postMessage article on MDN.

Co to sprowadza się do połączenia z jednej strony, aby opublikować wiadomość, np

otherWindow.postMessage(message, targetOrigin); 

a potem obsługi zdarzeń z drugiej strony:

window.addEventListener("message", receiveMessage, false); 

function receiveMessage(event) 
{ 
    alert("I got it!\n" + event.data); 
} 

IE6 i IE7 może możesz teraz wywoływać te okna, jeśli okna pochodzą z tej samej domeny, ale IE8 i nowsze będą prawdopodobnie wymagały użycia tego interfejsu API, i domyślam się, że inne przeglądarki wrócą w pełni z powrotem do znacznie bezpieczniejszej komunikacji mechanizm.

Biorąc pod uwagę sytuację, zdecydowanie zaleca się korzystanie z udostępnionej biblioteki w celu udostępnienia kodu (używając czegoś w stylu LAB.js lub require.js lub nawet tylko funkcji getScript() Jquery'ego), a następnie użyj przesyłania wiadomości między dokumentami system do wysyłania zdarzeń, zamiast funkcji zwrotnej, z której chcesz korzystać dzisiaj.

UPDATE


Istnieje polyfills dostępne dodać obsługę postMessage dla starszych przeglądarek. Ponieważ nie wykonujesz połączeń międzydomenowych, zacznę od Jquery postMessage plugin Ben Almana. Nie użyłem go, ale użyłem doskonałych wtyczek JQuery'a Bena. Powinien wrócić do wbudowanych metod, jeśli jest obsługiwany, i tylko podkładać w alternatywnych metodach w starszych przeglądarkach. To roszczenie do pracy w IE7 ...

Jeśli wtyczka Ben nie działa, możesz wypróbować easyXDM, ale wygląda na nieco bardziej skomplikowaną konfigurację.

+0

Myślę, że jest to najlepszy, zgodny z normami sposób postępowania. Ale jest to dla mnie problem, który nie jest obsługiwany w IE7. W każdym razie, myślę, że jesteś zwycięzcą. – Olegas

+0

Nie sądziłem, aby wyglądać wcześniej (byłam w stosunku do terminu), ale są pewne polyfills, aby zapewnić tę metodę w IE7. Zaktualizowałem odpowiedź, aby je uwzględnić. –

+0

Ładne lib, ale wykorzystuje on location.hash do przekazywania wiadomości ... W moim środowisku hash jest bardzo często używany do wewnętrznych potrzeb (takich jak nawigacja itp.). Ale można go zmodyfikować, aby wypełnić moje potrzeby i nie zepsuć niczego, co już działa. Dzięki. – Olegas

Powiązane problemy