DownloadFor MacOSX 10.5out of date — Get it on Github |
Read upGoogle Code homepage |
Get the codeVia Git |
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 and Ask your questions on the JSCocoa Google Group | |
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 |
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 :
// 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=\n' + 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 // 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. 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 |
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.
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 // 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 Add Swizzle in front of a method definition to swizzle it. To call the original method, call |
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
|
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 :
|
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 : |
2008 12 19 | Questions/Réponses sur JSCocoa [Developpez] |
2008 12 17 | JSCocoa Google Group Wanna talk about JSCocoa ? There's the place ! |
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 11 22 | JSCocoa interactive console for iPhone written by Kumagai Kentaro |
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 14 | Questions/Réponses sur JSCocoa [Cocoa.fr] |
2008 10 10 | Command line interpreter and REPL for JSCocoa written by Tom Robinson |
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. | |
Visit JSCocoa on Google Code, or check it out via Git : git clone git://github.com/parmanoir/jscocoa.git |