On 12.12.2008, at 16:45, Eoghan <eoghan...@gmail.com> wrote:
> 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?
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
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
On Sat, Dec 13, 2008 at 00:45, Bob Ippolito <b...@redivi.com> wrote:
> 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
On Sat, Dec 13, 2008 at 12:14, Eoghan <eoghan...@gmail.com> wrote:
> 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?
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
On Fri, Dec 12, 2008 at 21:46, Eoghan <eoghan...@gmail.com> wrote:
> 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...
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
On Sat, Dec 13, 2008 at 14:34, Arnar Birgisson <arn...@gmail.com> wrote:
> 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
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.
> 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
This one gets my vote.
cheers,
Arnar
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.
> 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).
> 5. More powerful partial:
> 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