out of date — Get it on Github

Write Cocoa apps in Javascript ! JSCocoa bridges Cocoa to JavascriptCore (WebKit's JS engine). It allows you to call C code, ObjC code, use C structs, and build Javascript classes inheriting from ObjC classes.





2010 03 22 Unicode names for classes and selectors I guess JSCocoa is really fully unicode now ! This only works well on the JSCocoa side, as on the ObjC side you'll have to get the class with objc_getClass([@"ファイナンス" UTF8String]) . I can't get it to call selectors yet. Still looks nice though !

2009 12 12 Catch ObjC exceptions in Javascript Following Rentzsch's post about how JSCocoa was broken, you can now catch ObjC exceptions in Javascript. try { var outOfRangeObject = [[NSArray arrayWithObjects:@"a", @"b", nil] objectAtIndex:-1] } catch(e) { // Prints NSRangeException log(e.name) } JSCocoa also had a 32bit bug when converting a number to an unsigned int, yielding 0 when converting -1. This is fixed.

2009 10 03 Objective-J syntax Trailing Objective-J and JSTalk, JSCocoa has a brand new way to call ObjC methods. This syntax works just like Objective-C, but in Javascript : // Standard Javascript way NSApplication.sharedApplication.delegate = myDelegate // ObjJ way [[NSApplication sharedApplication] setDelegate:myDelegate] // Mixed way [NSApplication sharedApplication].delegate = myDelegate // Multi param call var url = [NSURL instanceFileURLWithPath:@"/tmp" isDirectory:true] // Create a Javascript array containing an NSURL var array = [[NSURL instanceFileURLWithPath:@"/tmp" isDirectory:true]] This new syntax is done thanks to JSLint. Because of this, your code needs to conform to JSLint standards — if it doesn't, it won't run. You can disable JSLint (not recommended) with [yourJSCocoa setUseJSLint:NO] . Here's some colored code with lintex :

2009 09 22 Explore the Cocoa runtime List loaded classes, protocols, frameworks with these : JSCocoa.classes list all Cocoa classes

list all Cocoa classes JSCocoa.protocols all protocols

all protocols JSCocoa.imageNames all loaded frameworks List class data with these : MyClass.__subclasses a list of all classes inheriting from MyClass . Use MyClass.__subclassTree for a human readable version

a list of all classes inheriting from . Use for a human readable version MyClass.__classImage name of framework defining the class

name of framework defining the class MyClass.__derivationPath list superclasses

list superclasses MyClass.__methods , MyClass.__ivars , MyClass.__properties , MyClass.__protocols pretty much everything you wanted to know about a class ! These methods list all data from a class and from its superclasses. To get only this class' data, use the own-prefixed methods : MyClass.__ownMethods lists only methods defined by MyClass . Looking for methods // Find all NSArray methods starting with 'init' log(NSArray.__methods.filter(function (method) { return method.name.match(/^init/) })) // Same code, but only print method name log(NSArray.__methods.filter(function (method) { return method.name.match(/^init/) }).map(function(o){return o.name})) // Find NSObject methods defined in the AppKit framework log(NSObject.__methods.filter(function (method) { return method.framework.match(/AppKit/) } )) Showing class tree // Show NSButton superclasses log('NSButton superclasses=' + NSButton.__derivationPath) >NSObject, >NSResponder, >NSView, >NSControl, >NSButton // Show all CALayer subclasses in human readable form log('CALayer.subclassTree=

' + CALayer.__subclassTree) > CALayer > CAEmitterLayer > CAGradientLayer > CALayerHost > CAOpenGLLayer > NSOpenGLLayer > _NSOpenGLLayer > CAReplicatorLayer (snip)

2009 09 13 The new JSTalk website JSTalk is a way to script applications in Javascript. It's built on top of JSCocoa. Give it a try !

2009 09 06 Use JSCocoa in place of the existing WebKit bridge The WebKit bridge ( isSelectorExcludedFromWebScript, isKeyExcludedFromWebScript,... ) lets you call ObjC methods from Javascript. It gets the job done, but has a few limitations : it doesn't bridge hashes and doesn't let you use structures. By using initWithGlobalContext , JSCocoa can now be used inside a WebView in place of the WebKit bridge. This is the full JSCocoa monty in a webpage, with a small difference : there's a global OSX object to retrieve objects. // This is JSCocoa called from inside a WebView ! var objCDate = OSX.NSDate.alloc.init var point = new OSX.NSPoint(123, 456) var delegate = OSX.NSApplication.sharedApplication.delegate var array = delegate.testArray( ['hello', 'world', [4, 5, 6], 'end' ] ) Restricting access To prevent the webpage from calling certain methods, use JSCocoa's delegate methods. canGetGlobalProperty , canGetProperty , canCallFunction , canCallMethod will let you write anything from toll free passage to full lockdown. Check out JSCocoa / WebView sample code, by Fabien Franzen.

2009 09 06 x86_64, 64 bit support JSCocoa can now be used in 64 bit applications. Your code should mostly remain intact except for methods dealing with pointers : In 64 bit, CGFloat is now a double, so CGPoint , CGRect , NSColor all use doubles. Therefore when using methods like NSColor.getRed:(CGFloat *)red green:(CGFloat *)green blue:(CGFloat *)blue alpha:(CGFloat *)alpha or NSBezierPath.elementAtIndex:(NSInteger)index associatedPoints:(NSPointArray)points , make sure to allocate doubles, not floats. Call JSCocoa.runningArchitecture to know what you're running on. JSCocoa runs on x86_64 , i386 , PPC , iPhone and iPhone simulator .

2009 09 01 libffi-iphone This is under-the-hood stuff libffi allows calling any C-function or ObjC method at runtime. libffi-iphone is a stripped down version of libffi, tailored just for the iPhone. libffi-iphone includes source code for both the iPhone simulator and the iPhone itself. JSCocoa uses libffi-iphone internally. You may need it if you're porting a scripting language to the iPhone.

2009 09 01 JSCocoa works on the iPhone ! You can now use JSCocoa both on the iPhone and on the Mac. JSCocoa will give you runtime access to ObjC objects and let you call any method of any class. There are a few differences when creating your own ObjC classes in Javascript and when calling C functions, but you can work around these easily. the iPhone has no BridgeSupport files On the Mac, structures, enums, C functions can be used thanks to BridgeSupport files describing them : NSPoint , kCFAllocatorDefault , NSMakeRectRect are read by JSCocoa and made available in the Javascript context. On the iPhone, BridgeSupport files do not exist. You can still use structures, enums, C functions but they must be described in your own BridgeSupport file.

On the Mac, structures, enums, C functions can be used thanks to BridgeSupport files describing them : , , are read by JSCocoa and made available in the Javascript context. On the iPhone, BridgeSupport files do not exist. You can still use structures, enums, C functions but they must be described in your own BridgeSupport file. the iPhone has no mprotect To create a new ObjC class in Javascript, JSCocoa must create a new ObjC method for each method your overload. These methods are stored in a static pool, but they can be reused by any number of methods at runtime. Check out the iPhone sample on Github. JSCocoa works on the iPhone thanks to Philippe Charrière, Tim Burks, Jay Freeman, and Gary Hayenga. Thank you guys !

2009 08 11 Safe dealloc You can now safely overload dealloc in your classes. This was previously disabled as objects are deallocated when JavascriptCore triggers Garbage Collection, forbidding any script execution at collect time. To work around that, JSCocoa releases objects on the next run loop cycle, which calls dealloc at a safe time. This means any binding, notification request made can now be dismissed in dealloc , just like standard ObjC code. // A class whose targetValue will be bound with Cocoa Bindings class BindingsTarget < NSObject { // Dealloc will be called in the next run loop cycle right after JavascriptCore GC - (void)dealloc { this.unbind('targetValue') } // Declare a targetValue key Key targetValue } // Instantiate and bind to a source value var target = BindingsTarget.instance() target.bind_toObject_withKeyPath_options('targetValue', source, 'sourceValue', null)

2009 08 09 Manipulate WebViews with JSCocoa The WebKit bridge allows you to insert your own objects into a web page. JSCocoa now has a reverse bridge of its own, which allows you to manipulate a WebView's document. You can therefore load a web page then query it with code like log(window.document.body.innerHTML) . This is done with WebFrame 's globalContext . // Register a load delegate var loadDelegate = WebViewLoadDelegate.instance() view.frameLoadDelegate = loadDelegate // Load a web page webView.mainFrameURL = 'http://google.com' // Delegate class class WebViewLoadDelegate < NSObject { // WebKit will call this method upon page load completion - (void)webView:(WebView *)sender didFinishLoadForFrame:(WebFrame *)frame { // Global context is frame's window object var window = sender.mainFrame.globalContext // Change the background color of an element window.document.getElementById('someElement').style.backgroundColor = 'lime' // Call a Javascript method defined in the page window.callSomeJavascriptMethod('hello', 8) } }

2009 08 07 JSCocoaLoader allows you to create Espresso actions in Javascript using JSCocoa. Also check out Narwhal-jsc, a JSCocoa loader for Narwhal (server side Javascript). Both of them are open source on GitHub.

2009 04 11 Swizzle ! JSCocoa now lets you swizzle methods : class NSButton { // Swizzle an instance method of an existing class Swizzle- (void)drawRect:(NSRect)rect { // Draw something behind the button ... // Call original swizzled method, this will call NSButton's drawRect: this.Original(arguments) // Draw something in front of the button NSBezierPath.bezierPathWithOvalInRect(rect).stroke } } swizzling is replacing a method's implementation with our own. This example swizzles NSButton 's drawRect: with a Javascript function : each time a button must be drawn, the ObjC runtime will call this Javascript function. If you want to modify the behaviour of existing classes without deriving, swizzling is the way to go ! Thanks to JRSwizzle for the code. Add Swizzle in front of a method definition to swizzle it. To call the original method, call this.Original(arguments) .

2009 03 27 Introducing JSTalk, an alternative to AppleScript. Gus Mueller has released the first version of JSTalk, a way to make your application scriptable in Javascript. It also supports an Objective-C syntax. // JSTalk-enable your application [JSTalk listen]; // From the JSTalk editor you can then script it in Javascript var sketch = JSTalk.application("Sketch"); var doc = sketch.orderedDocuments()[0]; var rectangle = doc.makeNewBox(); rectangle.setWidth(100); rectangle.setHeight(100); // Or use an ObjC syntax var bezierPath = [NSBezierPath bezierPath]; [bezierPath curveToPoint:pointA controlPoint1:pointB controlPoint2:pointC]; [bezierPath fill]; Get JSTalk from Github !

2009 03 10 Use delegate methods to customize JSCocoa behaviour. // Check if getting property is allowed - (BOOL) JSCocoa:(JSCocoaController*)controller canGetProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception; // Custom handler for getting properties // Return a custom JSValueRef to bypass JSCocoa // Return NULL to let JSCocoa handle getProperty // Return JSValueMakeNull() to return a Javascript null - (JSValueRef) JSCocoa:(JSCocoaController*)controller getProperty:(NSString*)propertyName ofObject:(id)object inContext:(JSContextRef)ctx exception:(JSValueRef*)exception; These methods allow you to restrict access or customize behaviour. If you want to use JSCocoa as a plugin engine, implement canCallMethod to restrict method call, or canGetProperty and canSetProperty to restrict properties access. canGetGlobalProperty restricts access to ObjC classes, functions, structs and enums. After restricting access with the can* methods, you can use getProperty , setProperty , callMethod to bypass JSCocoa and implement custom behaviour to return custom values to Javascript. canLoadJSFile , canEvaluateScript restrict script loading. willEvaluateScript gives you a change to transform the input script before evaluation : use it to implement a custom syntax or expand your own macros.

2009 02 18 New class syntax inspired from Cappucino // Define a new class class MyClass < NSObject { // instance method - (int)addX:(int)x andY:(int)y { return x + y } // class method + (float)addFloatX:(float)x andFloatY:(float)y { return x + y } // Interface Builder outlet IBOutlet outlet1 // Interface Builder outlet using a Javacript notification IBOutlet outlet2 (newValue) { log('new value of outlet2=' + newValue) } // Interface Builder action, using sender as default parameter IBAction clickMe { log('Button clicked=' + sender) } // Interface Builder action, using custom parameter name IBAction clickMeToo(notifier) { log('Button clicked=' + notifier) } } There's some limitations on parameters (right now it's classes, structs, raw int/char/float) but these should go away in the future.

2009 02 18 JSLocalizedString defers localization to Javascript functions.

2009 02 13 Using Pointers JSCocoa can now handle pointers and memory buffers.

// Functions like NSOpenGLGetVersion(int*, int*) expect two pointers to int // JSCocoa detects pointer types and auto allocs required size var major = new outArgument var minor = new outArgument NSOpenGLGetVersion(major, minor) log('OpenGL version : ' + major + '.' + minor) // Using with structures var rect = new NSRect(10, 20, 30, 40) var rect1 = new outArgument var rect2 = new outArgument NSDivideRect(rect, rect1, rect2, 5, NSMinXEdge) log('Divided rect1=' + rect1) // Using with ObjC methods : scanning a string with NSScanner var scanner = NSScanner.scannerWithString('4.56 123') var extractedFloat = new outArgument scanner.scanFloat(extractedFloat) log('extracted=' + extractedFloat) // // Memory buffers : manually allocating memory and using it as data source or sink // // Data source : copy color components into our buffer // Allocate room for 4 floats var buffer = new memoryBuffer('ffff') // Extract components of a NSColor into our buffer color.get({ red : new outArgument(buffer, 0), green : new outArgument(buffer, 1), blue : new outArgument(buffer, 2), alpha : new outArgument(buffer, 3) }) log('Extracted red=' + buffer[0]) // Data sink : copy point coordinates into a NSBezierPath element // Allocate room for 3 points var buffer = new memoryBuffer('ffffff') // Set new point values buffer[0] = 10.0 buffer[1] = 5.0 ... ... // Fill a NSBezierPath element with our new coordinates path.setAssociatedPoints_atIndex(buffer, 1) Under the hood, JSCocoaOutArgument and JSCocoaMemoryBuffer handle all this.

2009 02 04 Write Cocoa plugins in almost anything Want more than Javascript ? Grayson Hansard wrote PluginManager, a project that enables you to write Cocoa plugins in AppleScript, F-Script, Javascript, Lua, Nu, Python and Ruby. "PluginManager is a series of classes that provides support for a vast number of scripting languages as well as standard Cocoa bundles. It is designed based on AddressBook's applescript plugin support but can be used in a wide number of ways. If nothing else, this project should provide an example into calling of scripts that you can adapt to your own applications."

2009 01 17 iPhone libffi Here's a better way than prederivation : Tim Burks advocates a pool of reconfigurable handlers. These handlers can be shared about amongst classes : first, gather the method type encodings from the classes' methods then generate Javascript callbacks from them. Great strategy !

2009 01 16 Elysium, a midi sequencer, uses JSCocoa for scripting. Check it out !

2009 01 15 iPhone JSCocoa now compiles on the iPhone, thanks to the Nu language's libffi. It crashes because it can't create Javascript methods callable by ObjC. ( mprotect ing the closure for libffi fails). Looks like there are 3 possibilities : Create an iPhone app and classes in ObjC then use JSCocoa to script these classes

Create dummy derived classes with dummy methods each calling their Javascript counterpart

Somehow make mprotect work Any other ideas ? parmanoir@gmail.com

2009 01 12 Multiple interpreters support JSCocoa can now create multiple versions of itself, each independant — just like each page in Safari has its interpreter. A document application can host one instance of JSCocoa in each document, each having its own variables separate from the others.

2009 01 10 Gus Mueller on JSCocoa and Acorn Plugins in JavaScript

2009 01 08 JSCocoa moves to Github Fork, branch, push and pull away ! I love Git, it's really a "what's changed" manager for directories used as source control. Files referenced once will exist only once, files moved will keep refering to the same object, and it's easy to use :

git add . to add the current directory,

git commit -a -m "new version!"; git push to send the new version to Github.

You can tag releases, easily branch from them, all of that locally ! If you don't know git it's worth to spend time to learn how it works. From Github you can fork JSCocoa and the fork queue will show branches and I'll be able to incorporate your changes back in JSCocoa.

2008 12 19 Questions/Réponses sur JSCocoa [Developpez]

2008 12 17 JSCocoa as a framework JSCocoa can now be added to an existing project as a framework — much simpler that before ! Checkout the latest version from svn.

2008 12 11 JSCocoa Garbage Collection

2008 11 28 JSCocoa Core Animation sample code

2008 10 24 JSCocoa working on iPhone simulator — check it out via svn

2008 10 15 Advice ? on JSCocoa iPhone

2008 10 15 Updated documentation

2008 10 08 Initial release

Everywhere dot

Just like in Ruby, call functions with or without parentheses. object.a().b().c() becomes object.a.b.c

Alas, if (a.b.c) won't work — use if (a.b.c()) until toBoolean() arrives

Cocoa NSString* appName = [[[NSWorkspace sharedWorkspace] activeApplication] valueForKey:@"NSApplicationName"];

JSCocoa var appName = NSWorkspace.sharedWorkspace.activeApplication.NSApplicationName

Instance

Tired of the alloc/init dance ? Use instance to get an object allocated, inited, and retained by Javascript's Garbage Collector

Cocoa [[NSButton alloc] initWithFrame:NSMakeRect(0, 0, 100, 40)];

Need to [ release] when done

JSCocoa NSButton.alloc.initWithFrame(NSMakeRect(0, 0, 100, 40))

Need to release() when done

NSButton.instance({ withFrame:NSMakeRect(0, 0, 100, 40) })

Handled by Javascript's GC

Get/Set

Instead of calling setVariable(newValue) , use Javascript's setter syntax : object.variable = newValue

Cocoa NSString* title = [window title];

[window setTitle:@"Hello !"];

JSCocoa var title = window.title

window.title = 'Hello !'

Call

Use a jQuery-like syntax to call multiple parameter methods

Cocoa [obj callWithParam1:@"Hello" andParam2:"World"];

JSCocoa obj.call({ withParam1:'Hello', andParam2:'World' })

obj['callWithParam1:andParam2:']('Hello', 'World')

obj.callWithParam1_andParam2('Hello', 'World' )

Fully Unicode

Name your variables in your native language !

JSCocoa function 追加する(最初の, 次の) { return 最初の+ 次の }

var 結果 = 追加する('こんにちは', '世界')

NSApplication.sharedApplication.keyWindow.title = 結果

Derive

A hash will define classes in one go, but you can add methods anytime after

Cocoa In .h @interface MyButton : NSButton { IBOutlet NSButton* myOutlet; } - (IBAction)myAction:(id)sender; @end In .m @implementation MyButton - (IBAction)myAction:(id)sender { ... } @end

JSCocoa defineClass('MyButton < NSButton', { myOutlet : 'IBOutlet' ,myAction : ['IBAction', function (sender) { ... }] })

Shorthand Overload

A quick way to overload methods : define a new class, use NSClass[method] = fn to overload methods like drawRect:

To call the parent method, one single syntax : this.Super(arguments) — no need to rewrite the method name !

JSCocoa MyButtonClass['drawRect:'] = function(rect) { // super call this.Super(arguments) // Add some custom drawing ... }

Integrate in Interface Builder

There's a catch here !

JSCocoa works with NIBs, but you'll need to manually add IBOutlet s and IBAction s while creating your interface. If you've ever wondered why there are + and - buttons in the Identity Inspector, wonder no more ! :)

Check it out — it's open

Wanna check in ? Mail me at parmanoir@gmail.com for write access.