Skip to content

Instantly share code, notes, and snippets.

@abock
Created August 11, 2015 22:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save abock/30b40e937c9507ba2f59 to your computer and use it in GitHub Desktop.
Save abock/30b40e937c9507ba2f59 to your computer and use it in GitHub Desktop.
//
// ViewController.cs
//
// Author:
// Aaron Bockover <abock@xamarin.com>
//
// Copyright 2015 Xamarin Inc. All rights reserved.
using System;
using Foundation;
using JavaScriptCore;
using AppKit;
using WebKit;
namespace JSExportTest
{
public partial class ViewController : NSViewController
{
public ViewController (IntPtr handle) : base (handle)
{
}
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// ideally we would subscribe to webView.JavaScriptContextCreated, but
// XM does not bind WebKit/JSC-ObjC bridge APIs:
// https://bugzilla.xamarin.com/show_bug.cgi?id=32975
webView.FinishedLoad += (sender, e) => {
var doc = webView.MainFrameDocument;
AttachListener (doc.GetElementById ("broken-button"), new BrokenDomEventListener ());
AttachListener (doc.GetElementById ("working-button"), new DomEventListener ());
};
webView.MainFrame.LoadHtmlString (
@"<html><body>
<button id='broken-button'>Broken</button>
<button id='working-button'>Working</button>
</body></html>",
null);
}
void AttachListener (DomElement elem, NSObject listener)
{
// should just be webView.MainFrame.JavaScriptContext (bug #32975)
var jsContext = JSContext.FromJSGlobalContextRef (webView.MainFrame.GlobalContext);
// should just be elem.JSValue (bug #32975)
var jsButton = JSValue.FromJSJSValueRef (elem.JSObject, jsContext);
jsButton.Invoke ("addEventListener",
JSValue.From ("click", jsContext), // event
JSValue.From (listener, jsContext), // listener
JSValue.From (true, jsContext) // useCapture
);
}
// The broken event listener's HandleEvent(JSValue) will not be invoked
// as it appears the XM runtime is blocking trying to convert the JSC
// value to a JSValue (or any NSObject...)
[Protocol]
interface IBrokenDomEventListener : IJSExport
{
[Export ("handleEvent:")]
void HandleEvent (JSValue evnt);
}
class BrokenDomEventListener : NSObject, IBrokenDomEventListener
{
public void HandleEvent (JSValue evnt)
{
Console.WriteLine ("JS -> C# Event: {0}", evnt);
}
}
// Luckily a workaround is to export a method to JSC with no arguments
// and access the current invocation's arguments via JSContext
[Protocol]
interface IDomEventListener : IJSExport
{
[Export ("handleEvent")]
void HandleEvent ();
}
class DomEventListener : NSObject, IDomEventListener
{
public void HandleEvent ()
{
Console.WriteLine ("JS -> C# Event: {0}", JSContext.CurrentArguments [0]);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment