JSCocoa brings Cocoa to Javascript.
It’s a bridge like PyObjC and RubyCocoa.
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.

Follow JSCocoa updates on Twitter
2009 04 11Swizzle ! 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 27Introducing 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 10Use 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 18New 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 18JSLocalizedString defers localization to Javascript functions.
2009 02 13Using 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 04Write 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 17iPhone 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 16Elysium, a midi sequencer, uses JSCocoa for scripting. Check it out !
2009 01 15iPhone 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. (mprotecting 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 12Multiple 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 10Gus Mueller on JSCocoa and Acorn Plugins in JavaScript
2009 01 08JSCocoa 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 19Questions/Réponses sur JSCocoa [Developpez]
2008 12 17JSCocoa Google Group Wanna talk about JSCocoa ? There's the place !
2008 12 17JSCocoa 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 11JSCocoa Garbage Collection
2008 11 28JSCocoa Core Animation sample code
2008 11 22JSCocoa interactive console for iPhone written by Kumagai Kentaro
2008 10 24JSCocoa working on iPhone simulator — check it out via svn
2008 10 15Advice ? on JSCocoa iPhone
2008 10 15Updated documentation
2008 10 14Questions/Réponses sur JSCocoa [Cocoa.fr]
2008 10 10Command line interpreter and REPL for JSCocoa written by Tom Robinson
2008 10 08Initial 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
CocoaNSString* appName = [[[NSWorkspace sharedWorkspace] activeApplication] valueForKey:@"NSApplicationName"];
JSCocoavar 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 IBOutlets and IBActions 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.
Visit JSCocoa on Google Code, or check it out via Git :

git clone git://github.com/parmanoir/jscocoa.git