<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="wordpress/2.3.3" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>Vacuous Virtuoso &#187; javascript</title>
	<link>http://lipidity.com</link>
	<description>Despotic Development</description>
	<pubDate>Tue, 23 Dec 2008 06:24:04 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.3.3</generator>
	<language>en</language>
			<item>
		<title>FancyForm - Pretty checkboxes and radios</title>
		<link>http://lipidity.com/web/javascript-checkbox-radio-replacement/</link>
		<comments>http://lipidity.com/web/javascript-checkbox-radio-replacement/#comments</comments>
		<pubDate>Tue, 28 Aug 2007 09:16:36 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Web]]></category>

		<category><![CDATA[CSS]]></category>

		<category><![CDATA[html]]></category>

		<category><![CDATA[javascript]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/feature/javascript-checkbox-radio-replacement</guid>
		<description><![CDATA[Styling form controls has always been limited with HTML and CSS. Not anymore. FancyForm provides the solution by letting you style checkboxes and radio buttons as you would any other elements, while degrading gracefully on older and non-graphical browsers.



Here&#8217;s an example of what&#8217;s possible with the script:



Not only does it let you style the checkboxes, [...]]]></description>
			<content:encoded><![CDATA[<p>Styling form controls has always been limited with HTML and CSS. Not anymore. <a href="http://dev.lipidity.com/fancy-form/">FancyForm</a> provides the solution by letting you style checkboxes and radio buttons as you would any other elements, while degrading gracefully on older and non-graphical browsers.</p>

<!--more-->

<p>Here&#8217;s an example of what&#8217;s possible with the script:</p>

<p class='centre'><img src="http://lipidity.com/images/fancy-20070828-190448.png" title="FancyForm styled checkboxes, before and after" alt="[styled checkboxes]" /></p>

<p>Not only does it let you style the checkboxes, you can also add your own custom JavaScript hooks, events, effects and a whole lot more.</p>

<p><a href="http://dev.lipidity.com/fancy-form/">Find out more</a> and please let me know of any bugs or possible ideas, or jump straight to <a href="http://dev.lipidity.com/fancy-form/demo/">the demo</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/web/javascript-checkbox-radio-replacement/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Javascript does Cocoa too</title>
		<link>http://lipidity.com/apple/javascript-cocoa-webkit/</link>
		<comments>http://lipidity.com/apple/javascript-cocoa-webkit/#comments</comments>
		<pubDate>Sat, 28 Jul 2007 08:07:49 +0000</pubDate>
		<dc:creator>Ankur</dc:creator>
		
		<category><![CDATA[Apple]]></category>

		<category><![CDATA[Cocoa]]></category>

		<category><![CDATA[javascript]]></category>

		<category><![CDATA[Mac]]></category>

		<category><![CDATA[Tutorial]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://dev.lipidity.com/dev/cocoa/javascript-cocoa-webkit</guid>
		<description><![CDATA[Running Objective-C code from Javascript

Java, Python and Ruby can access Cocoa APIs and Objective-C classes. What about the super-extensible yet severely under-appreciated Javascript? With the WebKit framework, you can access Objective-C from any script present in a HTML document.



A `WebScriptObject` is an Objective-C wrapper passed to your application from the scripting environment. You can&#8217;t create [...]]]></description>
			<content:encoded><![CDATA[<p><big>Running Objective-C code from Javascript</big></p>

<p>Java, Python and Ruby can access Cocoa APIs and Objective-C classes. What about the super-extensible yet severely under-appreciated Javascript? With the WebKit framework, you can access Objective-C from any script present in a HTML document.</p>

<!--more-->

<blockquote><p>A `WebScriptObject` is an Objective-C wrapper passed to your application from the scripting environment. You can&#8217;t create an instance directly, but you need to get a `WebScriptObject` by sending `webScriptObject` to a WebView.</p><cite>Paraphrase of <a href="http://developer.apple.com/documentation/Cocoa/Reference/WebKit/Classes/WebScriptObject_Class/Reference/Reference.html#//apple_ref/doc/c_ref/WebScriptObject" title="WebScriptObject Class Reference" target="_blank">WebScriptObject Overview</a></cite></blockquote>

<p>This class, <code>WebScriptObject</code>, lets you &#8220;talk&#8221; and &#8220;listen&#8221; to Javascript (or any other code allowable inside <acronym title="Hyper Text Markup Language">HTML</acronym> <code>&lt;script&gt;</code> tags). That is, you can run Javascript code or functions in the WebView, but you can also let the Javascript run Objective-C methods.</p>

<p>This is the same way Dashboard widgets interact with Cocoa plugins. You know how you access <code>window.widget</code> in your Javascript? That&#8217;s an Objective-C class you&#8217;re referencing. The WebKit framework provides all the necessary classes and functionality for this interaction, making this seemingly difficult task ridiculously easy.</p>

<h4>Exposing an Objective-C class to the scripting environment</h4>

<p>Exposing a class to the scripting environment is very easy. You can use key-value coding methods (for example, <code>setValue:forKey:</code> and <code>valueForKey:</code>) to get and set the properties of a <code>WebScriptObject</code>. These will be accessible as children of the window object in Javascript. Use the <code>removeWebScriptKey:</code> method to remove a scripting object property.</p>

<p>As an example, let&#8217;s say we have a class <code>NSFoo</code>. We&#8217;ve linked to the WebKit framework and <code>webView</code> is a <code>WebView</code>.</p>

<p>We use the delegate method <code>webView:windowScriptObjectAvailable:</code> to ensure that the <code>WebScriptObject</code> is available before we start using it. Then we expose an instance of <code>NSFoo</code> to the scripting environment:</p>

<pre><code>- (void)webView:(WebView *)sender windowScriptObjectAvailable: (WebScriptObject *)windowScriptObject {
    NSFoo *myFoo = [[NSFoo alloc] init];

    scriptObject = windowScriptObject;
    [scriptObject setValue:myFoo forKey:@"foo"];
}
</code></pre>

<p>Now you can access <code>foo</code> through javascript;</p>

<pre><code>&lt;script language='text/javascript'&gt;
var myFoo = foo;
&lt;/script&gt;
</code></pre>

<h4>Allow Javascript access</h4>

<p>For obvious security reasons, no methods or KVC keys are exposed to the Javascript environment by default. This means at this stage while <code>window.foo</code> exists, you can&#8217;t do much with it. To allow Javascript to send messages or get / set properties, the following two class methods need to be utilized:</p>

<pre><code>+ (BOOL)isSelectorExcludedFromWebScript:(SEL)aSelector;
+ (BOOL)isKeyExcludedFromWebScript:(const char *)name;
</code></pre>

<p>So for example, if we want to allow Javascript to send a <code>bar:</code> message to a class, all we have to do is add the following class method to the implementation:</p>

<pre><code>+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector {
    if ( selector == @selector(bar:) ) {
        return NO;
    }
    return YES;
}
</code></pre>

<p>Now running <code>foo.bar_(0)</code> in Javascript will be equivalent to running <code>[myFoo bar:0]</code> in Objective-C. Why the underscore? Selectors accessed from Javascript are renamed using the following rules:</p>

<ul>
<li>Any colon (&quot;:&quot;) in the Objective-C selector is replaced by an underscore (&quot;_&quot;).</li>
<li>Any underscore in the Objective-C selector is prefixed with a dollar sign (&quot;$&quot;).</li>
<li>Any dollar sign in the Objective-C selector is prefixed with another dollar sign.</li>
</ul>

<p>So a method called <code>doAction:(id)action withThing:(id)thing</code> will be turned into <code>doAction_withThing_(action,thing)</code>, while <code>do$This:</code> will become <code>do$$This_</code>. This is often pretty ugly and inconvenient. Fortunately, the Javascript name for the selectors can be changed.</p>

<h4>Change Javascript selector names</h4>

<p>Using <code>+ (NSString *)webScriptNameForSelector:(SEL)sel</code>, we can change the name of the selector in Javascript:</p>

<pre><code>+ (NSString *)webScriptNameForSelector:(SEL)sel
{
    if (sel == @selector(bar:))
        return @"bar";
    return nil;
}
</code></pre>

<p>Now we can run <code>foo.bar(0)</code> in Javascript to equal <code>[myFoo bar:0]</code>. Here are a few more examples:</p>

<pre><code>+ (NSString *)webScriptNameForSelector:(SEL)sel
{
    if (sel == @selector(performTransition))
        return @"performTransition";    // widget.performTransition()
    else if (sel == @selector(prepareForTransition:))
        return @"prepareForTransition"; // widget.prepareForTransition(arg)
    else if (sel == @selector(setPreference:forKey:))
        return @"setPreferenceForKey";  // widget.setPreferenceForKey(pref,key)
    else if (sel == @selector(preferenceForKey:))
        return @"preferenceForKey";     // widget.preferenceForKey(key)
    return nil;
}
</code></pre>

<p>If you want to expose all the instance methods of the class to the scripting environment, just return <code>NO</code> without doing any checks:</p>

<pre><code>+ (BOOL)isSelectorExcludedFromWebScript:(SEL)selector { return NO; }
</code></pre>

<p>Remember: selectors are converted into Javascript functions, so even if the method doesn&#8217;t need any arguments, you still need to add the parenthesis at the end for the Javascript; eg. <code>[object doMethod]</code> becomes <code>object.doMethod()</code>.</p>

<h4>Key-Value-Coding from Javascript</h4>

<p>Exposing KVC keys is a similar procedure. Here we&#8217;re giving access to the &#8220;name&#8221; property:</p>

<pre><code>+ (BOOL)isKeyExcludedFromWebScript:(const char *)property {
    if (strcmp(property, "name") == 0) {
        return NO;
    }
    return YES;
}
</code></pre>

<p>Now in Javascript, we can read and write <code>foo.name</code>. Reading <code>foo.name</code> will be equivalent to <code>[myFoo name]</code> and writing to it (<code>foo.name = "A big foo"</code>) will be the same as running <code>[myFoo setName:@"A big foo"]</code>.</p>

<p>As before, just <code>return NO</code> without any checks to allow all KVC keys to be accessed from the scripting environment.</p>

<h3>Summary</h3>

<ul>
<li>Load WebKit.framework which contains the classes <code>WebView</code> and <code>WebScriptObject</code>.</li>
<li>Send <code>setValue:forKey:</code> to a <code>WebScriptObject</code>; makes an object available to the scripting environment.</li>
<li>Implement <code>+isSelectorExcludedFromWebScript:</code> and <code>+isKeyExcludedFromWebScript:</code> and return NO to allow the scripting environment to run a method or access a key.</li>
<li>Use <code>webScriptNameForSelector:</code> / <code>webScriptNameForKey:</code> to specify the names of your methods / keys as seen by Javascript.</li>
</ul>

<h3>Further reading</h3>

<ul>
<li><a href="http://developer.apple.com/documentation/Cocoa/Reference/WebKit/ObjC_classic/index.html">WebKit Documentation</a></li>
<li><a href="http://developer.apple.com/documentation/Cocoa/Reference/WebKit/Protocols/WebScripting_Protocol/index.html#//apple_ref/doc/uid/TP40003837">WebScripting Documentation</a></li>
<li><a href="http://developer.apple.com/documentation/AppleApplications/Conceptual/SafariJSProgTopics/Tasks/ObjCFromJavaScript.html">Obj-C From JavaScript</a></li>
<li><a href="http://will.thimbleby.net/script/">TurtleScript</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://lipidity.com/apple/javascript-cocoa-webkit/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>
