title: WebKit2 and DomDocument/JavaScriptCore (Python3)
body: <p>I am converting a Python3 application to use WebKit2 instead of WebKit (which is no longer available in Debian Buster).</p>
  
  <p>In the application the user can (de)select check boxes which I read from the Python3 application. In the original code I could simply get the DomDocument of the Webview and iterate through the child objects to return the value of the object with a given name (sample code below).</p>
  
  <p>In WebKit2 the <a href="https://webkitgtk.org/reference/webkitgtk/stable/webkitgtk-webkitwebview.html#webkit-web-view-get-dom-document" rel="nofollow noreferrer">get_dom_document</a> function is no longer available and the <a href="https://webkitgtk.org/reference/webkit2gtk/stable/" rel="nofollow noreferrer">WebKit2 documentation</a> is not clear on how to proceed.</p>
  
  <p>Does anybody know how to get the DomDocument from a WebKit2 Webview or another way to iterate through all objects by name and get their value?</p>
  
  <p><strong>Sample code DomDocument from WebKit Webview:</strong></p>
  
  <pre><code>def get_element_values(self, element_name):
      values = []
      doc = self.get_dom_document()
      elements = doc.get_elements_by_name(element_name)
      for i in range(elements.get_length()):
          child = elements.item(i)
          value = child.get_value().strip()
          if not child.get_checked():
              value = ''
          if value:
              values.append(value)
      return values
  </code></pre>
  
  <p>Note: "self" is the WebKit.Webview.</p>
  
  <p><strong>[EDIT]</strong></p>
  
  <p>I have been experimenting with this. First I tried to get the DomDocument by getting the WebPage object first. I found WebView.get_page_id() and WebKit2WebExtension.get_page(page_id) but unfortunately that gave me this error: AttributeError: 'gi.repository.WebKit2WebExtension' object has no attribute 'get_page'.</p>
  
  <p>After that I tried JavaScriptCore and insert JavaScript with WebView.run_javascript() and WebView.run_javascript_finish(). I get a JavaScriptResult object back but when I try to get the value with .get_value() I get this error: TypeError: Couldn't find foreign struct converter for 'JavaScriptCore.Value'.</p>
  
  <p>There was a user with the same issue <a href="https://stackoverflow.com/questions/37553701/webkit2-javascriptresult-get-value-throws-exception-typeerror-couldnt-find">here</a>, but the proposed solution was too complicated for me as well.</p>
  
  <p>Here's the code I used for testing (check the get_element_values() and javascript_finished() functions):</p>
  
  <pre><code>#! /usr/bin/env python3
  
  # WebKit2 reference: https://webkitgtk.org/reference/webkit2gtk/stable
  # Code examples: https://github.com/sidus-dev/poseidon/blob/master/poseidon.py
  
  import gi
  gi.require_version('WebKit2', '4.0')
  gi.require_version('WebKit2WebExtension', '4.0')
  from gi.repository import WebKit2, WebKit2WebExtension, Gtk
  from os.path import exists
  import webbrowser
  import re
  
  
  class SimpleBrowser(WebKit2.WebView):
      def __init__(self):
          WebKit2.WebView.__init__(self)
  
          # Get version
          self.webkit_ver = WebKit2.get_major_version(), WebKit2.get_minor_version(), WebKit2.get_micro_version()
          print(("WebKit2 Version: {0}".format('.'.join(map(str, self.webkit_ver)))))
  
          # Signals
          self.connect('decide-policy', self.on_decide_policy)
          #self.connect("load_changed", self.on_load_changed)
          self.connect("load-failed", self.on_load_failed)
          self.connect('button-press-event', lambda w, e: e.button == 3)
  
          # Settings
          s = self.get_settings()
          s.set_property('allow_file_access_from_file_urls', True)
          s.set_property('enable-spatial-navigation', False)
          s.set_property('enable_javascript', True)
  
  
      def show_html(self, html_or_url):
          if exists(html_or_url):
              matchObj = re.search('^file:\/\/', html_or_url)
              if not matchObj:
                  html_or_url = "file://{0}".format(html_or_url)
          matchObj = re.search('^[a-z]+:\/\/', html_or_url)
          if matchObj:
              self.load_uri(html_or_url)
          else:
              self.load_html(html_or_url)
          self.show()
  
      def get_element_values(self, object, element_name):
          # JavaScript &gt; dead end :(
          # https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebView.html#webkit-web-view-run-javascript
          js = 'var e = document.getElementsByName("' + element_name + '"); var r = []; var c = 0; ' \
               'for (var i = 0; i &lt; e.length; i++) { if (e[i].checked) { r[c] = e[i].value; c++;} }'
          self.run_javascript(js, None, self.javascript_finished, None);
          return
  
          # DOM &gt; dead end :(
          # https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebPage.html
          # https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebView.html#webkit-web-view-get-page-id
          page_id = self.get_page_id()
          print((page_id))
          # https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebExtension.html#webkit-web-extension-get-page
          # AttributeError: 'gi.repository.WebKit2WebExtension' object has no attribute 'get_page'
          web_page = WebKit2WebExtension.get_page(page_id)
          print((web_page))
  
      def javascript_finished(self, webview, result, user_data):
          # https://webkitgtk.org/reference/webkit2gtk/stable/WebKitWebView.html#webkit-web-view-run-javascript-finish
          js_result = self.run_javascript_finish(result)
          print(("&gt;&gt;&gt; js_result = %s" % str(js_result)))
          # TypeError: Couldn't find foreign struct converter for 'JavaScriptCore.Value'
          value = js_result.get_value()
          print(("&gt;&gt;&gt; value = %s" % str(value)))
  
      def on_decide_policy(self, webview, decision, decision_type):
          # User clicked on a &lt;a href link: open uri in new tab or new default webview
          if (decision_type == WebKit2.PolicyDecisionType.NAVIGATION_ACTION):
              action = decision.get_navigation_action()
              action_type = action.get_navigation_type()
              if action_type == WebKit2.NavigationType.LINK_CLICKED:
                  decision.ignore()
                  uri = action.get_request().get_uri()
                  # Open link in default browser
                  webbrowser.open_new_tab(uri)
          else:
              if decision is not None:
                  decision.use()
  
      def on_load_changed(webview, event):
          # TODO: get html of loaded page
          if event == WebKit2.LoadEvent.FINISHED:
              resource = webview.get_main_resource()
              resource.get_data()
              html = resource.get_data_finish(None)
              print(html)
  
      def on_load_failed(webview, event, url, error):
          print("Error loading", url, "-", error)
  
  html = '&lt;html&gt;&lt;body style="background-color:#E6E6E6;"&gt;&lt;h1&gt;WebKit2 Test&lt;/h1&gt;' \
         '&lt;p&gt;&lt;a href="https://solydxk.com"&gt;link&lt;/a&gt;&lt;/p&gt;&lt;form onsubmit="return false;"&gt;' \
         '&lt;input type="checkbox" name="chktst" value="checkbox1" checked /&gt; CheckBox 1&lt;br /&gt;' \
         '&lt;input type="checkbox" name="chktst" value="checkbox2" /&gt; CheckBox 2&lt;br /&gt;' \
         '&lt;button onclick="alert(show_values());"&gt;JS Show Values&lt;/button&gt;' \
         '&lt;/form&gt;' \
         '&lt;script&gt;' \
         'function show_values() {' \
         'var e = document.getElementsByName("chktst"); var r = []; var c = 0;' \
         'for (var i = 0; i &lt; e.length; i++) {' \
         '    if (e[i].checked) { r[c] = e[i].value; c++;}' \
         '}return r;}' \
         '&lt;/script&gt;' \
         '&lt;/body&gt;&lt;/html&gt;'
  
  
  win = Gtk.Window()
  win.connect("delete-event", Gtk.main_quit)
  win.set_default_size(600,400)
  
  webview = SimpleBrowser()
  webview.show_html(html)
  box = Gtk.Box.new(Gtk.Orientation.VERTICAL, 0)
  button = Gtk.Button(label="Python Show Values")
  button.connect("clicked", webview.get_element_values, 'chktst')
  
  win.add(box)
  box.pack_start(webview, True, True, 0)
  box.pack_start(button, False, False, 1)
  
  win.show_all()
  
  Gtk.main() 
  </code></pre>
  
  <p><strong>[EDIT2]</strong></p>
  
  <p>In Debian Stretch you need to install the packages from backports:</p>
  
  <pre><code>sudo apt-get install -t stretch-backports gir1.2-javascriptcoregtk-4.0 gir1.2-webkit2-4.0 libjavascriptcoregtk-4.0-18 libwebkit2gtk-4.0-37  libwebkit2gtk-4.0-37-gtk2
  </code></pre>
  
  <p>Now, WebKit2.JavascriptResult.get_js_value() will return a JavaScriptCore.Value object. I will test this further and post back an answer if I find one.</p>
  
  <p>Check this bug report: <a href="https://bugs.webkit.org/show_bug.cgi?id=136989" rel="nofollow noreferrer">https://bugs.webkit.org/show_bug.cgi?id=136989</a></p>