How to get navigation callback from iframe in WebGadget?

Everything else that doesn't fall into one of the other PB categories.
User avatar
Kukulkan
Addict
Addict
Posts: 1352
Joined: Mon Jun 06, 2005 2:35 pm
Location: germany
Contact:

How to get navigation callback from iframe in WebGadget?

Post by Kukulkan »

Hi,

I display user HTML content in the webgadget (cross platform). For this, I cover it into some iframe. There I want to use sandbox feature to disable JavaScript (for security). But I need to open links from within this document to be opened by myself (I want to open the system web-browser with clicked target to allow links to be displayed independent of me).

Then I did this test code, puzzled together mainly from forum posts (eg from Shardik, Wilbert and others). It loads some document and iframe from my website. Containing only links to PureBasic website. You can see directly here.

Code: Select all

; PureBasic 5.46 LTS / Unicode

CompilerSelect #PB_Compiler_OS
  CompilerCase #PB_OS_Windows
    ; ----------------------
    ; -- WINDOWS SPECIFIC --
    ;{----------------------
    Procedure EnsureJSforWebGadget(WebgadgetID.i)
      ; not needed on Windows
    EndProcedure
    
    Procedure SetNavigationCallback(WebGadget.i, *CallBackFunction)
      ; Somehow works by default on Windows
      SetGadgetAttribute(WebGadget.i, #PB_Web_NavigationCallback, 
                         *CallBackFunction)
    EndProcedure
    ;}
    
  CompilerCase #PB_OS_Linux
    ; --------------------
    ; -- LINUX SPECIFIC --
    ;{--------------------
    #G_TYPE_INT = 6 << 2
    ImportC ""
      g_object_get_property(*Object.GObject, PropertyName.P-UTF8, 
                            *PropertyValue)
    EndImport
    ImportC "-lwebkitgtk-3.0"
       webkit_web_view_get_settings(*WebView)
       webkit_web_view_set_settings(*WebView, *WebkitSettings)
       webkit_web_navigation_action_get_original_uri(*NavigationAction)
       webkit_web_policy_decision_ignore(*PolicyDecision)
       webkit_web_policy_decision_use(*PolicyDecision)
    EndImport
    ImportC "-lgobject-2.0"
      g_signal_connect_data(*Instance, Signal.P-UTF8, *Callback, *UserData,
                            *ClosureNotify, ConnectFlags.I)
    EndImport
    
    ProcedureC linNavigationCallback(*WebView, *Frame, *Request,
                                  *NavigationAction, *PolicyDecision, *UserCallback)
      Protected URL.s = PeekS(webkit_web_navigation_action_get_original_uri(*NavigationAction),
                              -1, #PB_UTF8)
      
      CallFunctionFast(*UserCallback, 0, @URL.s)
      ; webkit_web_policy_decision_ignore(*PolicyDecision)
      webkit_web_policy_decision_use(*PolicyDecision)
    EndProcedure
       
    Procedure EnsureJSforWebGadget(WebgadgetID.i)
      ; Enable JavaScript support in GTK3 WebGadgets
      ; (dont know why it is off by default?)
      Protected WebkitSettings.i = webkit_web_view_get_settings(GadgetID(WebgadgetID.i))
      Protected Value.GValue
      If WebkitSettings
         Value\g_type = #G_TYPE_INT
         g_object_get_property(WebkitSettings, "enable-scripts", @Value)
         If g_value_get_int_(@Value) = 0
            g_value_set_int_(@Value, 1)
            g_object_set_property_(WebkitSettings, "enable-scripts", @Value)
            webkit_web_view_set_settings(GadgetID(WebgadgetID.i), WebkitSettings)
         EndIf
       EndIf
    EndProcedure
    
    Procedure SetNavigationCallback(WebGadget.i, *CallBackFunction)
      g_signal_connect_data(GadgetID(0), "navigation-policy-decision-requested",
                            @linNavigationCallback(), *CallBackFunction, 0, 0)
    EndProcedure
    ;}
    
  CompilerCase #PB_OS_MacOS
    ; ----------------------
    ; -- MAC OSX SPECIFIC --
    ;{----------------------
    Global AppDelegate = CocoaMessage(0, CocoaMessage(0, 0, "NSApplication sharedApplication"), "delegate")
    Global DelegateClass = CocoaMessage(0, AppDelegate, "class")
    
    Global *macCallbackFunction
    ProcedureC macPolicyDecisionMaker(Object.I, Selector.I, WebView.I,
      ActionInformation.I, Request.I, *FrameName, Listener.I)
      Protected *URL = CocoaMessage(0, Request, "URL")
      Protected URL.s = PeekS(CocoaMessage(0,
        CocoaMessage(0, *URL, "absoluteString"), "UTF8String"), -1, #PB_UTF8)
      
      Debug URL.s
      
      CallFunctionFast(*macCallbackFunction, 0, @URL.s)
      
      ; CocoaMessage(0, Listener, "ignore")
      CocoaMessage(0, Listener, "use")
    EndProcedure

    class_addMethod_(DelegateClass, sel_registerName_("webView:" +
                     "decidePolicyForNavigationAction:request:frame:decisionListener:"),
                     @macPolicyDecisionMaker(), "v@:@@@@@")
    
    Procedure EnsureJSforWebGadget(WebgadgetID.i)
      ; not needed on MacOS
    EndProcedure
    
    Procedure SetNavigationCallback(WebGadget.i, *CallBackFunction)
      ; Somehow works by default on Linux
      *macCallbackFunction = *CallBackFunction
      CocoaMessage(0, GadgetID(WebGadget.i), "setPolicyDelegate:", AppDelegate)
    EndProcedure
    ;}
    
CompilerEndSelect

; ---------------
; -- TEST CODE --
;{---------------

Procedure NavigationCallback(Gadget.i, Url.s) 
  Debug "Detected URL: [" + Url.s + "]"
  ; IMPORTANT: Gadget.i is only returned on Windows! Linux and Mac is 0.
  ProcedureReturn #True
EndProcedure

If OpenWindow(0, 0, 0, 600, 300, "WebGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered) 
  WebGadget(0, 10, 10, 580, 280, "http://x-beliebig.info/Download/iframetest.html")
  EnsureJSforWebGadget(0)

  SetNavigationCallback(0, @NavigationCallback())
  Repeat 
  Until WaitWindowEvent() = #PB_Event_CloseWindow 
EndIf
;}
Results:

Windows main frame:
I get only target="_self" navigation callbacks.
target="_blank" does not fire callbacks, but opens new web-browser!

Windows iframe:
I get only target="_self" navigation callbacks.
target="_blank" does nothing

Linux main frame:
I get only target="_self" navigation callbacks.
target="_blank" does nothing

Linux iframe:
I get no navigation callbacks at all.

MacOS main frame:
I get only target="_self" navigation callbacks.
target="_blank" does nothing

MacOS iframe:
I get no navigation callbacks at all.

I wish I was able to get ALL navigation events. I also really need to get the events from inside the iframe, too.

Do you see any idea about how to get and handle ALL navigation events of all target="n" variants? I'm also able to reqrite all target="_blank" to be target="_self" if this helps a little. On Windows this will work, but not on MacOS or Linux (not getting any event at all).

JavaScript is not an option, because the sandbox iframe will stop all execution of JS by the code in the iframe (this is what I finally want). I also considered removing all script code from the HTML, but it is impossible. There are soooo many ways to enbed JS (urls, events, tags etc). It is also to slow for big documents.