Discussion:
connectEach shortcut
Eoghan
2008-12-12 16:45:42 UTC
Permalink
I often use the following utility function:

function connectEach(iterable, signal, dest, func){
forEach(iterable, function(el){
connect(el, signal, dest, func);
});
}

It might be used as follows:

connectEach($$('#my-ul li'), 'onclick', function(e){
// do sumn'
});

rather than slightly more unwieldy:
forEach($$('#my-ul li'), function(el){
connect(el, 'onclick', function(e){
// do sumn'
});
});

Is it a good candidate to include in the Signal api?

Eoghan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Arnar Birgisson
2008-12-12 19:20:48 UTC
Permalink
Hi
Post by Eoghan
connectEach($$('#my-ul li'), 'onclick', function(e){
// do sumn'
});
forEach($$('#my-ul li'), function(el){
connect(el, 'onclick', function(e){
// do sumn'
});
});
Is it a good candidate to include in the signal api?
I can definitely see the use case, but IMO this is one of the cases
where I'd not want to add since forEach is not that much typing. In my
mind this the whole point of having a functional, composable API such
as the iter module.

Just my 2000 ISK

cheers,
Arnar

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Eoghan
2008-12-12 21:46:51 UTC
Permalink
Hi
   connectEach($$('#my-ul li'), 'onclick', function(e){
               // do sumn'
        });
   forEach($$('#my-ul li'), function(el){
           connect(el, 'onclick', function(e){
                   // do sumn'
               });
        });
Is it a good candidate to include in the signal api?
I can definitely see the use case, but IMO this is one of the cases  
where I'd not want to add since forEach is not that much typing. In my  
mind this the whole point of having a functional, composable API such  
as the iter module.
Just my 2000 ISK
cheers,
Arnar
I agree.
After consideration of generalisation, maybe what I'm looking for is a
version of `partial` that can take out of order arguments, something
along the following lines:

forEach($$('#my-ul li'), partial(connect,
MochiKit.Base.placeholder, 'onclick', function(e){
// do sumn'
}));

Although I'm not sure what the implementation of partial would look
like in order to support out of order placeholder arguments...

Eoghan

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Arnar Birgisson
2008-12-13 14:34:45 UTC
Permalink
Hi,
Post by Eoghan
After consideration of generalisation, maybe what I'm looking for is a
version of `partial` that can take out of order arguments, something
forEach($$('#my-ul li'), partial(connect,
MochiKit.Base.placeholder, 'onclick', function(e){
// do sumn'
}));
Although I'm not sure what the implementation of partial would look
like in order to support out of order placeholder arguments...
Ah, yes - I have *often* felt the need for this. Here is one possible
implementation:

function p() {
var args = Array.prototype.slice.call(arguments);
appendChildNodes('logpane', DIV(null, args.join(', ')));
}

var _ = new Object();

var invalidNumberOfArgs = new Error("Number of given arguments does
not match number of unknown arguments.");

function partial() {
var args = Array.prototype.slice.call(arguments);
var f = args.shift();
var unknowns = filter(MochiKit.Base.partial(operator.seq, _), args).length;
return function() {
if (arguments.length != unknowns) {
throw invaldNumberOfArgs;
}
var passed = Array.prototype.slice.call(arguments);
var filled = map(function (a) {
if (a === _) {
return passed.shift();
} else {
return a;
}
}, args);
return f.apply(this, filled);
}
}

function test() {
p('start');

var x = partial(p, "one", _, "three");
x('two');

x = partial(p, _, _, "three", _);
x('one', 'two', 'four');

p('done');
}

addLoadEvent(test);


As for permuting arguments, I have some ideas.. let me think about them a bit.

cheers,
Arnar

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Arnar Birgisson
2008-12-13 15:13:31 UTC
Permalink
Hi again all,
Post by Arnar Birgisson
As for permuting arguments, I have some ideas.. let me think about them a bit.
Here is an implementation of partial that does out-of-order arguments,
both via unnumbered placeholders and numbered ones (see the function
test() for examples):

// I'm also attaching an html file that you can load in your browser
to see it in action.

function p() {
var args = Array.prototype.slice.call(arguments);
appendChildNodes('logpane', DIV(null, args.join(', ')));
}

function _(n) {
return {'__argument_index': n};
}

var invalidNumberOfArgs = new Error("Number of given arguments does
not match number of unknown arguments.");
var mixingNumberedWithUnnumbered = new Error("Cannot mix numbered
argument placeholders with numbered ones.");
var invalidNumberedPlaceholders = new Error("Numbered placeholders
must be sequential (i.e. no gaps) starting from 0 or 1.");

function partial() {
var args = Array.prototype.slice.call(arguments);
var f = args.shift();

var unnumbered = filter(MochiKit.Base.partial(operator.seq, _), args).length;
var indexes = map(itemgetter('__argument_index'), filter(function (a) {
return typeof a == 'object' && '__argument_index' in a;
}, args));

if (unnumbered > 0 && indexes.length > 0) {
throw mixingNumberedWithUnnumbered;
}

if (indexes.length == 0) {
return function() {
if (arguments.length != unnumbered) {
throw invalidNumberOfArgs;
}
var passed = Array.prototype.slice.call(arguments);
var filled = map(function (a) {
if (a === _) {
return passed.shift();
} else {
return a;
}
}, args);
return f.apply(this, filled);
}
} else {
// some sanity checks
var sorted = indexes.slice(0);
sorted.sort();
if (sorted[0] == 1) {
indexes = map(function (x) {return x-1;}, indexes);
sorted = map(function (x) {return x-1;}, sorted);
} else if (sorted[0] != 0) {
throw invalidNumberedPlaceholders; // must start with 0 or 1
}
// make sure there are no gaps
if (!every(izip(count(), sorted), function (pair) { return
pair[0] == pair[1]})) {
throw invalidNumberedPlaceholders; // can't have gaps
}
return function() {
if (arguments.length != indexes.length) {
throw invalidNumberOfArgs;
}
var passed = Array.prototype.slice.call(arguments);
var i = 0;
var filled = map(function (a) {
if (typeof a == 'object' && '__argument_index' in a) {
return passed[indexes.shift()];
} else {
return a;
}
}, args);
return f.apply(this, filled);
}
}
}

function test() {
p('start');

var x = partial(p, "one", _, "three");
x('two');

x = partial(p, _, _, "three", _);
x('one', 'two', 'four');

x = partial(p, _);
x('one');

x = partial(p, 'one');
x();

x = partial(p, _(2), _(1));
x('two', 'one');

// for convenience:
function flip(f) { return partial(f, _(2), _(1)); }
x = flip(p);
x('two', 'one');

// can also be zero based
x = partial(p, _(1), _(0));
x('two', 'one');

x = partial(p, 'one', _(3), 'three', _(1), 'five', _(2));
x('four', 'six', 'two');

p('done');
}

addLoadEvent(test);


cheers,
Arnar

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Eoghan
2008-12-13 23:26:12 UTC
Permalink
Post by Arnar Birgisson
Hi,
Post by Eoghan
After consideration of generalisation, maybe what I'm looking for is a
version of `partial` that can take out of order arguments, something
   forEach($$('#my-ul li'), partial(connect,
MochiKit.Base.placeholder, 'onclick', function(e){
                // do sumn'
           }));
Although I'm not sure what the implementation of partial would look
like in order to support out of order placeholder arguments...
Ah, yes - I have *often* felt the need for this. Here is one possible
function p() {
   var args = Array.prototype.slice.call(arguments);
   appendChildNodes('logpane', DIV(null, args.join(', ')));
}
var _ = new Object();
var invalidNumberOfArgs = new Error("Number of given arguments does
not match number of unknown arguments.");
function partial() {
   var args = Array.prototype.slice.call(arguments);
   var f = args.shift();
   var unknowns = filter(MochiKit.Base.partial(operator.seq, _), args).length;
   return function() {
       if (arguments.length != unknowns) {
           throw invaldNumberOfArgs;
       }
       var passed = Array.prototype.slice.call(arguments);
       var filled = map(function (a) {
           if (a === _) {
               return passed.shift();
           } else {
               return a;
           }
       }, args);
       return f.apply(this, filled);
   }
}
function test() {
   p('start');
   var x = partial(p, "one", _, "three");
   x('two');
   x = partial(p, _, _, "three", _);
   x('one', 'two', 'four');
   p('done');
}
addLoadEvent(test);
As for permuting arguments, I have some ideas.. let me think about them a bit.
cheers,
Arnar
Very nice, I thought to implement this myself but baulked.
May I suggest MochiKit.Base.__ as the name of the placeholder
variable.
I can't imagine needing the permuting version myself.

Eoghan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Arnar Birgisson
2008-12-14 00:53:58 UTC
Permalink
Post by Eoghan
May I suggest MochiKit.Base.__ as the name of the placeholder
variable.
If Bob or Per want to include this, I'd like to change it to make it
compatible with the current partial (namely, any extra parameters
passed on the call itself will just be tacked on the end).

MochiKit.Base.__ sounds good to me. Just _ is more likely to step on
someone's toes.
Post by Eoghan
I can't imagine needing the permuting version myself.
Actually, 95% of the cases I've wanted this I just wanted flip
(reverse the order of two parameters). At the very least I'd like to
see

function flip(f) {
return function (x,y) { return f(y,x); };
}

included. In other cases, I have definitely had use for the generic
permuting version.

cheers,
Arnar

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Per Cederberg
2008-12-14 10:42:14 UTC
Permalink
I think it is an interesting idea to be able to bind any argument
position. Think I mentioned it earlier in the 1.5 API discussion that
we now have quite a few variants of bind-like functions -- bind,
bindLate, bindMethods, forwardCall, partial, method, methodCaller...

Too many for my taste, so I think it is time to revisit these API:s.
Perhaps something more generic than the current bind() might be a good
idea? Or perhaps it would have an API that is too complex? Don't know
really.

I'll look into the code posted by Arnar later on (no much time right
now) and comment on the specifics then.

Cheers,

/Per
Post by Arnar Birgisson
Post by Eoghan
May I suggest MochiKit.Base.__ as the name of the placeholder
variable.
If Bob or Per want to include this, I'd like to change it to make it
compatible with the current partial (namely, any extra parameters
passed on the call itself will just be tacked on the end).
MochiKit.Base.__ sounds good to me. Just _ is more likely to step on
someone's toes.
Post by Eoghan
I can't imagine needing the permuting version myself.
Actually, 95% of the cases I've wanted this I just wanted flip
(reverse the order of two parameters). At the very least I'd like to
see
function flip(f) {
return function (x,y) { return f(y,x); };
}
included. In other cases, I have definitely had use for the generic
permuting version.
cheers,
Arnar
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Bob Ippolito
2008-12-13 00:45:06 UTC
Permalink
Post by Arnar Birgisson
Hi
Post by Eoghan
connectEach($$('#my-ul li'), 'onclick', function(e){
// do sumn'
});
forEach($$('#my-ul li'), function(el){
connect(el, 'onclick', function(e){
// do sumn'
});
});
Is it a good candidate to include in the signal api?
I can definitely see the use case, but IMO this is one of the cases
where I'd not want to add since forEach is not that much typing. In my
mind this the whole point of having a functional, composable API such
as the iter module.
Just my 2000 ISK
Personally I think it's useful, but I would rather have the connect
take a selector as a string instead of a list. Makes it much easier to
track down when the lookup happens in-connect.

connectAll("#my-ul li", "onclick", ...);

(not sold on the name)

We could even have the existing API do this if passed a list, but
perhaps that's a bit too magical.

connect(["#my-ul li"], "onclick", ...);

The other problem is that the return signature has to change for
disconnect, or we have to allow for a different kind of disconnect.

-bob

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Arnar Birgisson
2008-12-13 02:56:35 UTC
Permalink
Hi,
Post by Bob Ippolito
connect(["#my-ul li"], "onclick", ...);
I agree this looks a little bit too magical. Perhaps more "expected"
would be to allow the first argument to be a list, but in that case a
list of elements (or strings passed to getElement). The selector case
is then simply:

connect($$("#my-ul li"), "onclick", ...);

As for the return, this would return a list. I.e.

connect(elements, event, handler) {
if (isIterable(elements)) {
return map(function (el) {connect(el, event, handler);}, elements);
} else {
// current connect code for a single element
}
}

cheers,
Arnar

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Eoghan
2008-12-13 12:14:42 UTC
Permalink
Post by Bob Ippolito
Personally I think it's useful, but I would rather have the connect
take a selector as a string instead of a list. Makes it much easier to
track down when the lookup happens in-connect.
connectAll("#my-ul li", "onclick", ...);
(not sold on the name)
We could even have the existing API do this if passed a list, but
perhaps that's a bit too magical.
connect(["#my-ul li"], "onclick", ...);
The other problem is that the return signature has to change for
disconnect, or we have to allow for a different kind of disconnect.
-bob
What I like in MochiKit is that you can pass an id to be looked up by
getElement anywhere a DOM node is expected.

Some functions, such as connect, could adapt naturally to receiving a
list instead of a node (others, such as swapDOM, do not).

This might be a crazy suggestion, but if the goal here is to integrate
selectors throughout MochiKit, a nice way to do it might be to use
findDocElements instead of getElement when a string is passed instead
of a node.
Implemented along the lines of the following (thanks Arnar):

connect(src, sig, objOrFunc, funcOrStr) {
// removed: src = MochiKit.DOM.getElement(src);
if (typeof(src) == 'string') {
return map(function (el) { return connect(el, sig,
objOrFunc, funcOrStr);}, MochiKit.Selector.findDocElements(src));
} else {
// current connect code for a single element
}
}

This would be backwards incompatible as current code such as:
connect('my-id', 'onclick', ....)
Would have to be rewritten as:
connect('#my-id', 'onclick', ....)

IMO think this would give MochiKit a lot of the ease of use of JQuery,
where selectors are pervasive.

Is this a bridge too far?

Eoghan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Arnar Birgisson
2008-12-13 13:57:12 UTC
Permalink
Hi,
Post by Eoghan
connect('my-id', 'onclick', ....)
connect('#my-id', 'onclick', ....)
IMO think this would give MochiKit a lot of the ease of use of JQuery,
where selectors are pervasive.
Is this a bridge too far?
The backwards incompatibility thing is a bit too much I think. One
workaround would be to make selector automagically interpret a string
like "bla" as "#bla" -- but I don't think I'd vote for such as
suggestion though :)

cheers,
Arnar

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Amit Mendapara
2008-12-15 05:13:13 UTC
Permalink
Look at the MochiKit.Query module of the MochiKit Extensions (http://
launchpad.net/mochikit-ext).
It provides jQuery style signal functions...

MochiKit.Query('#my-ul li').click(function(evt){
// handle events here
});

or

MochiKit.Query('#my-ul li').click(some_callback);

then you can signal to matched elements by simply calling...

MochiKit.Query('#my-ul li').click();

Regards
--
Amit
    function connectEach(iterable, signal, dest, func){
        forEach(iterable, function(el){
                connect(el, signal, dest, func);
            });
    }
    connectEach($$('#my-ul li'), 'onclick', function(e){
                // do sumn'
         });
    forEach($$('#my-ul li'), function(el){
            connect(el, 'onclick', function(e){
                    // do sumn'
                });
         });
Is it a good candidate to include in the Signal api?
Eoghan
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Eoghan
2008-12-16 14:47:32 UTC
Permalink
So I guess there's a few options. Taking the connect/onclick example:

0. Existing:
forEach($$('#my-ul li'), function(el){
connect(el, 'onclick', func);
});

1. JQuery like:
Query('#my-ul li').click(func);

2. Modify the lookup by id convention to lookup by selector + map:
connect('#my-ul li', 'onclick', func);

3. As above but double the namespace '-)
connectAll('#my-ul li', 'onclick', func);

4. Map if passed an array-like
connect($$('#my-ul li'), 'onclick', func);

5. More powerful partial:
forEach($$('#my-ul li'), partial(connect, __, 'onclick', func));
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Arnar Birgisson
2008-12-16 15:49:08 UTC
Permalink
Post by Eoghan
4. Map if passed an array-like
connect($$('#my-ul li'), 'onclick', func);
This one gets my vote.

cheers,
Arnar

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---
Per Cederberg
2008-12-18 08:27:34 UTC
Permalink
Post by Eoghan
connect('#my-ul li', 'onclick', func);
Yes, changing these lookups would break the current API. But it
wouldn't be impossible to create a migration path with decent
backwards compatibility if we really want to.

The more important issues with this, I think, is that we would have to:

* Change every MochiKit.DOM, Style, Signal, Visual... function that
accepts the current shortcut to work properly on node lists (not just
individual nodes).

* Add the MochiKit.Selector module as a dependency for the DOM module
(actually a circular dependency).

I'm not very convinced that this is the right direction, but on the
other side I hardly ever use the current shortcut either. My own use
cases all rely on keeping object maps with direct references to my DOM
nodes.
Post by Eoghan
4. Map if passed an array-like
connect($$('#my-ul li'), 'onclick', func);
This looks like the fastest way forward right now.

But instead of connecting signal handlers all over, I'd personally do
the following instead:

var func = function (evt) {
var li = evt.target();
if (li.tagName == null || li.tagName.toUpperCase() != "LI") {
li = getFirstParentByTagAndClassName(evt.target(), "LI");
}
... whatever you wanted to do ...
}
connect('my-ul', 'onclick', func);

Agreed that using getFirstParentByTagAndClassName() gets a bit messy,
since it doesn't check the specified node for a match (just the
parents).
Post by Eoghan
forEach($$('#my-ul li'), partial(connect, __, 'onclick', func));
We probably need the more powerful partial or bind, but I'm not so
sure about this API.

Cheers,

/Per

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "MochiKit" group.
To post to this group, send email to ***@googlegroups.com
To unsubscribe from this group, send email to mochikit+***@googlegroups.com
For more options, visit this group at http://groups.google.com/group/mochikit?hl=en
-~----------~----~----~----~------~----~------~--~---

Loading...