Pieces of my core javascript library: The Lambda Framework
Guest Author: Einar Otto Stangvik
Will Code for Nuts
Following up on my previous post, about the Script Loader piece of my core library, here’s a couple more central pieces for the stuff I’m about to tell about in posts to follow.
On the spot in this post is the lambda library. Simply put, a lambda here means an expression with placeholders for parameters to come. As such, it’s not unlike the closures we already have in javascript, but this does up the stakes a little bit.
Closures allow us to define inline functions, and bind expressions to said function’s parameters as well as those of the outside scope, ex:
function doSomething()
{
var someGreeting = "Hi";
var closure = function(name) { alert(someGreeting + " " + name); }
closure("yourself"); // Should alert "Hi yourself"
}
… which is all old news.
With the following lambda library, I could construct the following fulent expression tree:
var verification = _.first().is(10);
alert(verification(10)); // Should alert 'true'
// The same as a closure:
// var verificationClosure = function(x) { return x == 10; }
// A more advanced verification (although hardly the best we can do):
var advancedVerification = _.and(_.first().is(10), _.second().isnt(_.first()));
alert(advancedVerification(10, 10)); // Should alert 'false'
alert(advancedVerification(10, 20)); // Should alert 'true'
This may seem like utter gibberish, but in certain cases it can be useful in order to define a relatively clear set of rules for an operation to take place. Specifically I’m using this in a library which establishes relationships between abstracted gui elmements. What I’m able to do is say, with an expression tree, that:
Given squares A and B; B can be dragged into A if B isn’t already a child of A, and it has a certain inherent property.
This is actual code from my DropBox SharePoint plugin (I’ll showcase that later), which uses another library of mine, SPDrag (that essentially makes standard SharePoint UI elements drag’n'droppable).
grep.spdrag.connect(
/* target container */ $("table.ms-listviewtable"),
/* conditions */ [
_.and(
_.item().is_dropbox_item(),
_.target().is_document_library(),
_.not(_.item().is_child_of(_.target()))
)
],
/* action on drop */ function(element)
{
self._deployFileToDocumentLibrary(element);
});
Connect, in other words, is a function which accepts three parameters: a target container (in this case the a SharePoint list view), a condition for it to allow an element to be dragged onto it, and what’s supposed to happen if they are dropped there.
The second parameter, the conditions, is a further abstracted lambda expression tree, which introduces elements specific to the SPDrag library. item, the dragged element; target, the target container; and a HTML DOM type function called is_child_of which is here used to disallow dropping elements from the target container back onto the target container.
Arguably, the syntax can get complex, especially with the logical operators preceding the operands rather than being between them, but it has also the ability to be very clear and precise on the domain operation at hand, avoiding as much of the function / closure / parameter clutter as possible.
Without further ado, here’s the lambda core, which can be (and are) abstracted into domain specific lambda expressions. In the case of the above item element, that’s actually a specialization of first in the base lambda library, but that’s for the library implementing the domain specific lambda to know only. As the end user, you’d only have to consider item representing the item.
if(!window.grep) window.grep = {};
if(!window.grep.lambda)
{
window.grep.lambda = window._ =
{
nth:function(x){return window.grep.tools.extend(function(){return arguments[x-1];},this);},
first:function(){return this.nth(1);},
second:function(){return this.nth(2);},
is:function(x){var c=this;return function(){return (typeof(x)=="function"?x.apply(this,arguments):x)==c.apply(this,arguments);}},
isnt:function(x){var c=this;return function(){return (typeof(x)=="function"?x.apply(this,arguments):x)!=c.apply(this,arguments);}},
gt:function(x){var c=this;return function(){return (typeof(x)=="function"?x.apply(this,arguments):x)c.apply(this,arguments);}},
and:function(){var a=arguments;return function(){for(var x=0;x
This is an excerpt from the tool library, which contains the extend function used in the above lambda lib.
if (!window.grep) window.grep = {};
if (!window.grep.tools)
{
window.grep.tools = {
extend: function()
{
var r = arguments[0];
for(var i = 1; i < arguments.length; ++i)
{
for(var x in arguments[i])
{
r[x] = arguments[i][x];
}
}
return r;
}
}
}
Guest Author: Einar Otto Stangvik
Will Code for Nuts
Einar is a SharePoint architect and avid developer based in Oslo, Norway. Once a deep diving C++ programmer, and previous Microsoft MVP for that, he's now mostly turned to the world of .NET and web frontends, with primary focus on C#, WCF, Silverlight and JavaScript.
View all entries in this series: EinarOttoStangvik - Will Code for Nuts» Entries in this series:- Pieces of my core javascript library: The Script Loader
- Pieces of my core javascript library: The Lambda Framework
- Connecting SharePoint UI Elements: SPDrag and the DropBox
- Assigning dynamic ids to HTML and Script elements - Client Side!