Cacao/WebKit, avendo la finestra“.open()” per i link JavaScript apertura di un’istanza di Safari

Sto costruendo davvero di base di Cacao applicazione che utilizza WebKit, per visualizzare un Flash/Silverlight applicazione all’interno di esso. Molto di base, senza intenzioni per essere un browser stesso.

Finora sono stato in grado di ottenere per aprire basic link html (<a href="..." />) in una nuova istanza di Safari usando

[[NSWorkspace sharedWorkspace] openURL:[request URL]];

Ora la mia difficoltà è l’apertura di un link in una nuova finestra di Safari quando window.open() è utilizzato in JavaScript. Io “credo” (e, per questo, sono stato hacking del codice e sono sicuro se in realtà ho fatto o non) ho avuto questo tipo di lavoro, impostando la WebView è policyDelegate e nell’attuazione delle sue

-webView:decidePolicyForNavigationAction:request:frame:decisionListener:

metodo delegato. Tuttavia, questo ha portato ad alcuni malfunzionamenti.

In modo semplice domanda, di cosa ho bisogno per fare in modo che quando window.open() è chiamato, il link viene aperto in una nuova finestra di Safari.

Grazie

Grande punto, io sono normalmente una .NET developer e ho lavorato con Cacao/WebKit per un paio di giorni.

  • Sto avendo lo stesso problema. Sembra essere un bug che webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener non viene chiamato.
InformationsquelleAutor FireWire | 2008-11-06

 

7 Replies
  1. 9

    Che ho fatto dal progresso la scorsa notte e ha bloccato parte del mio problema.

    Sto già utilizzando webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener: e ho ottenuto di lavorare con i tag di ancoraggio, tuttavia il metodo non sembra mai chiamato quando JavaScript è richiamato.

    Tuttavia quando window.open() è chiamato webView:createWebViewWithRequest:request è chiamato, ho provato a forzare la finestra per aprire in Safari qui però la richiesta è sempre null. Così non riesco mai a leggere l’URL.

    Ho fatto qualche ricerca in giro, e questo sembra essere un noto “misfeature” tuttavia io non sono stato in grado di trovare un modo per aggirare questo.

    Da quello che ho capito createWebViewWithRequest ti dà la possibilità di creare il nuovo webview, l’url richiesto è poi inviato al nuovo webView per essere caricato. Questa è la migliore spiegazione che ho potuto trovare.

    Così, mentre molte persone hanno fatto notare questo problema, devo ancora vedere qualsiasi soluzione che si adatta alle mie esigenze. Cercherò di scavare un po ‘ più nel decidePolicyForNewWindowAction di nuovo.

    Grazie!

    • Questo è molto utile. Grande lavoro, l’uomo! 🙂
  2. 6

    Bene, io sto gestendo con la creazione di un manichino webView, l’impostazione è frameLoad delegato di una classe personalizzata che gestisce

    - (void)webView:decidePolicyForNavigationAction:actionInformation :request:frame:decisionListener:

    e si apre una nuova finestra.

    codice :

    - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
        //this is a hack because request URL is null here due to a bug in webkit        
        return [newWindowHandler webView];
    }

    e NewWindowHandler :

    @implementation NewWindowHandler
    
    -(NewWindowHandler*)initWithWebView:(WebView*)newWebView {
        webView = newWebView;
    
        [webView setUIDelegate:self];
        [webView setPolicyDelegate:self];  
        [webView setResourceLoadDelegate:self];
    
        return self;
    }
    
    - (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
        [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]];
    }
    
    -(WebView*)webView {
        return webView;
    }
  3. 4

    Sembra che ci sia un bug con webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener: in quanto la richiesta è sempre nil, ma c’è una robusta soluzione che funziona sia con normale target="_blank" link javascript quelli.

    Fondamentalmente io uso un altro effimero WebView per gestire il nuovo caricamento di pagina. Simile a Yoni Shalom, ma con un po ‘ più di zucchero sintattico.

    Per l’uso prima di impostare un oggetto delegato per le WebView, in questo caso sono l’impostazione di me, come delegato:

    webView.UIDelegate = self;

    Poi basta implementare il webView:createWebViewWithRequest: delegato metodo e usare il mio blocco a base di API per fare qualcosa quando viene caricata una nuova pagina, in questo caso sto ad aprire la pagina in un browser esterno:

    -(WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
        return [GBWebViewExternalLinkHandler riggedWebViewWithLoadHandler:^(NSURL *url) {
            [[NSWorkspace sharedWorkspace] openURL:url];
        }];
    }

    Che è molto bello. Ecco il codice per la mia classe. Intestazione:

    // GBWebViewExternalLinkHandler.h
    // TabApp2
    //
    // Created by Luka Mirosevic on 13/03/2013.
    // Copyright (c) 2013 Goonbee. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @class WebView;
    
    typedef void(^NewWindowCallback)(NSURL *url);
    
    @interface GBWebViewExternalLinkHandler : NSObject
    
    +(WebView *)riggedWebViewWithLoadHandler:(NewWindowCallback)handler;
    
    @end

    Implementazione:

    // GBWebViewExternalLinkHandler.m
    // TabApp2
    //
    // Created by Luka Mirosevic on 13/03/2013.
    // Copyright (c) 2013 Goonbee. All rights reserved.
    //
    
    #import "GBWebViewExternalLinkHandler.h"
    
    #import <WebKit/WebKit.h>
    
    @interface GBWebViewExternalLinkHandler ()
    
    @property (strong, nonatomic) WebView                           *attachedWebView;
    @property (strong, nonatomic) GBWebViewExternalLinkHandler      *retainedSelf;
    @property (copy, nonatomic) NewWindowCallback                   handler;
    
    @end
    
    @implementation GBWebViewExternalLinkHandler
    
    -(id)init {
        if (self = [super init]) {
            //create a new webview with self as the policyDelegate, and keep a ref to it
            self.attachedWebView = [WebView new];
            self.attachedWebView.policyDelegate = self;
        }
    
        return self;
    }
    
    -(void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener {
        //execute handler
        if (self.handler) {
            self.handler(actionInformation[WebActionOriginalURLKey]);
        }
    
        //our job is done so safe to unretain yourself
        self.retainedSelf = nil;
    }
    
    +(WebView *)riggedWebViewWithLoadHandler:(NewWindowCallback)handler {
        //create a new handler
        GBWebViewExternalLinkHandler *newWindowHandler = [GBWebViewExternalLinkHandler new];
    
        //store the block
        newWindowHandler.handler = handler;
    
        //retain yourself so that we persist until the webView:decidePolicyForNavigationAction:request:frame:decisionListener: method has been called
        newWindowHandler.retainedSelf = newWindowHandler;
    
        //return the attached webview
        return newWindowHandler.attachedWebView;
    }
    
    @end

    Licenza Apache 2.

    • Vecchio ma fantastico, questo bug sembra essere ancora presente e la risposta era esattamente quello che mi serviva.
    • Ancora una buona correzione.
  4. 2

    Non parlare di che tipo di comportamento irregolare si sta vedendo. Una rapida possibilità, è che quando si implementa il metodo delegato hai dimenticato di dire la webview si sta ignorando il clic chiamando ignora il metodo del WebPolicyDecisionListener che è stato passato il delegato, che può mettere le cose in uno strano stato.

    Se non è questo il problema, quanto controllo hai più il contenuto che si sta visualizzando? La politica delegato offre un facile meccanismi di filtro di tutte le risorse, i carichi (come hai scoperto), e tutti i nuovi finestra si apre via webView:decidePolicyForNewWindowAction:richiesta:newFrameName:decisionListener:. Per le finestre.aprire le chiamate dovrebbero imbuto attraverso che, come qualsiasi altra cosa che innesca una nuova finestra.

    Se ci sono altri si apre la finestra che si desidera mantenere all’interno della vostra applicazione, è di fare un po ‘ di lavoro in più. Uno degli argomenti passati il delegato è un dizionario contenente informazioni sull’evento. Insie che dizionario il WebActionElementKey avrà un dizionario che contiene un numero di dettagli, tra cui l’originale dom contenuto del link. Se volete curiosare lì si può prendere l’effettivo elemento DOM, e controllare il testo del href vedere se inizia con finestra.aperto. Che è un po ‘ pesante, ma se si vuole avere un controllo più dettagliato darà a voi.

    • Grazie per il feedback Louis, ho controllato nelle ultime due link, e ho guardato loro, purtroppo non credo che funzionerà, in quanto la finestra.open non è in linea all’interno di un tag di ancoraggio. Viene richiamato tramite un metodo Javascript che viene chiamato da Silverlight.
  5. 2

    Leggendo tutti i post, sono venuto con la mia soluzione semplice, tutte le funzioni individuali sono nella stessa classe,qui si apre un link con il browser.

    - (WebView *)webView:(WebView *)sender createWebViewWithRequest:(NSURLRequest *)request {
    
        return [self externalWebView:sender];
    }
    
    
    
    
    - (void)webView:(WebView *)sender decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener
    {
        [[NSWorkspace sharedWorkspace] openURL:[actionInformation objectForKey:WebActionOriginalURLKey]];
    }
    
    -(WebView*)externalWebView:(WebView*)newWebView
    {
         WebView *webView = newWebView;
    
        [webView setUIDelegate:self];
        [webView setPolicyDelegate:self];
        [webView setResourceLoadDelegate:self];
        return webView;
    }
  6. 0

    Spiegazione:

    Windows creato da JavaScript attraverso la finestra.aprire passare attraverso createWebViewWithRequest.
    Per le finestre.bandi di risultato in un createWebViewWithRequest: null richiesta, poi un percorso di cambiamento che WebView.

    Per ulteriori informazioni, vedere questo post su WebKit mailing list.

  7. 0

    Un’alternativa alla restituzione di una nuova WebView e in attesa per il suo loadRequest: metodo chiamato, ho finito di sovrascrivere il window.open funzione nella WebView è JSContext:

    Prima, ho impostato il mio controller il WebFrameLoadDelegate di WebView:

    myWebView.frameLoadDelegate = self;

    Quindi, nel metodo delegato, ho sovrascritto il window.open funzione, e io in grado di elaborare l’URL c’è invece.

    - (void)webView:(WebView *)webView didCreateJavaScriptContext:(JSContext *)context forFrame:(WebFrame *)frame{
    context[@"window"][@"open"] = ^(id url){
            NSLog(@"url to load: %@", url);
        };
    }

    Questo mi permette di gestire la richiesta, tuttavia avevo bisogno senza la necessità di scomodi per creare ulteriori visualizzazioni web delle.

Lascia un commento