Using ExtJs’ bind to partially apply a function

Because of my work I dabbled a bit in ExtJs and I wanted to show you something that I need quite regularly. It has become common practice in JavaScript to pass around function object like no man’s business. Which is quite alright. But sometimes you prepare a function for another library. Usually this looks something like this:

var somefunction = function (arg1, arg2, arg3, arg4, arg5) {
  console.log(arg1, arg2, arg3, arg4, arg5);
};

var caller = function (fObject) {
  return fObject(1,2);
};

caller(somefunction);
// 1 2 undefined undefined undefined

But you can’t pass any argument to somefunction (because JavaScript is not Haskell and you cannot build partially applied thunks). So how do we partially apply some values? ExtJs gives us quite a powerful tool:

caller(Ext.bind(somefunction, undefined /* this is the bound scope which, in this case, is not needed */, [3,4,5], true));
// 1 2 3 4 5

Usually, you would bind the scope to “this” but in this rather trivial case, we don’t need it. The “true” at the end is to tell Ext to append the new parameters (3, 4 and 5) rather than overwriting the existing ones. But we can put them any place we want.

caller(Ext.bind(somefunction, undefined, [3,4,5], 1));
// 1 3 4 5 2

We also can, which is rather cool, apply them in instead and therefore “cancel out” other paramters by leaving the last bind-parameter as undefined:

caller(Ext.bind(somefunction, undefined, [3,4,5]));
// 3 4 5 undefined undefined

You can, of course, save your partially applied function objects:

var partiallyAppliedFunction = Ext.bind(somefunction, undefined, [3,4,5]);
partiallyAppliedFunction();
// 3 4 5 undefined undefined

But remember: The function is saved as reference at binding time (and not by name). Therefore changing the original function won’t change anything:

somefunction = function () { console.log('I no longer do as I am told.') };
partiallyAppliedFunction();
// 3 4 5 undefined undefined

You can also construct function objects from anonymous functions/closures that way, for whatever reason you would need that:

var SomeBoundAnonymousFunction = Ext.bind(function (a) { console.log(a); }, undefined, [3,4,5]);
SomeBoundAnonymousFunction();
// 3

cool, huh?!

Using sass with html5 boilerplate

This article is about how easy it is to use Sass with the html5 boilerplate.

So you installed Sass, which, on Fedora, was as easy as

sudo yum install rubygem-sass

but you will find your way in Sass’s documentation.

Then you downloaded html5boilerplate (from initializr.com) and the ant buildscript. Unpack your html5 boilerplate into a folder and unpack the buildscript in the subdirectory “build” so that your directory structure looks something like this:

.
|-- build
|-- css
|-- img
|-- index.html
|-- js
`-- robots.txt

now you edit the file “build/config/project.properties” and uncomment the line “build.css.scss            = true” (which was line 42 on my system) and you are done.

Now you can use Sass in your main.css wherever you want and the build script will compile it to valid css. Your browser does not understand Sass so you can no longer test your site without building it. You should use the basics buildtarget for ant to generate your css code for testing (and not optimizing images and such):

cd build
ant basics

You’ll find the compiled version in your “publish” subfolder where you can look at your changes.

reCaptcha inside a with jQuery ajax() or load() dynamically loaded object

For the German version of this article, please look here.

The Problem: you want to use reCaptcha with the JS (JavaScript) or php-Api in in a with jQuery ajax() or load() dynamically loaded area. But: the reCaptcha doesn’t appear.

My use case looked something like this:

contakt.html (abridged):

<div id="form"></div>
<script>$("#form").load("mail.php?ajax");</script>

mail.php (abridged): 

<?php
// here is other code
echo '<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script><div id="recaptcha"></div>';
echo '<script>Recaptcha.create("my_public_key", "recaptcha", {theme: "red"});</script>';
// other code
?>

And this, like I said, doesn’t work.

The problem:
google’s reCaptcha API uses the document.write() function for inserting reCaptcha in to the document tree. This function is not available in this case, when the content is loaded dynamically with jQuery. document.write() therefore has to be replaced with its jQuery equivalent.

This means you either have to maintain your own version of the api or you work this out dynamically. Our solution looked something like this:

mail.php (abridged): 

echo '<script type="text/javascript" src="jsapi.php"></script><div id="recaptcha"></div>';

jsapi.php (complete):

<?php
$api = file_get_contents('http://www.google.com/recaptcha/api/js/recaptcha_ajax.js');
$api = str_replace('document.write','$("body").append',$api);
echo $api;
?>

The replacing could be made manually and is highly trivial. Therefore I did not attach a changed version of the recaptcha_ajax.js. You probably need to do something about the header to make the api cacheable for the browser again, but this was not our focus.

reCaptcha innerhalb eines mit jQuery ajax() oder load() dynamisch geladenen Bereichs

For the English version of this article, please look here.

Das Problem: man möchte reCaptcha über die JS (JavaScript) oder php-Api in einen durch den jQuery-Befehl ajax() eingefügten Bereich verwenden. Aber: das reCaptcha taucht nicht auf.

Mein Use-Case sah so aus:

kontakt.html (auszug):

<div id="form"></div>
<script>$("#form").load("mail.php?ajax");</script>

mail.php (auszug): 

<?php
// here is other code
echo '<script type="text/javascript" src="http://www.google.com/recaptcha/api/js/recaptcha_ajax.js"></script><div id="recaptcha"></div>';
echo '<script>Recaptcha.create("my_public_key", "recaptcha", {theme: "red"});</script>';
// other code
?>

 Und das funktioniert, wie bereits erwähnt, nicht.

Das Problem:
googles reCaptcha-Api verwendet zum Einfügen des Objekts das document.write(), was an dieser Stelle im Dokumentenbaum durch die Verwendung von jQuery nicht verfügbar ist. Die Lösung ist “denkbar” einfach. Googles document.write muss durch einen jQuery-Befehl ersetzt werden.

Das heißt, mann muss entweder eine eigene Version der Api maintainen, oder man arbeitet dynamisch. Bei uns sah die Lösung konzeptionell so aus:

mail.php (auszug): 

echo '<script type="text/javascript" src="jsapi.php"></script><div id="recaptcha"></div>';

jsapi.php (vollständig):

<?php
$api = file_get_contents('http://www.google.com/recaptcha/api/js/recaptcha_ajax.js');
$api = str_replace('document.write','$("body").append',$api);
echo $api;
?>

Die Ersetzung manuell vorzunehmen ist höchst trivial, darum habe ich jetzt keine geänderte recaptcha_ajax.js angehängt. Insgesamt könnte man an den headern noch etwas machen, dass das Caching-Verhalten des Browsers korrekt wird, das war aber nicht Fokus.