From: Scott Sauyet on
toby.oconnell(a)gmail.com wrote:
> Scott Sauyet wrote:
>
>> I'm also curious about the dynamic API you present.  Obviously that's
>> one clear way to avoid failing calls to API methods.  What are the
>> advantages over the method that provides a static API that in the
>> absence of browser support reverts to dummy code that does nothing,
>> returns empty arrays or false results for any of its calls?
>
> Usinging such a static API can keep code from blowing up but it can
> also obscure API misuse and cause other problems.

It can, and it's also more flexible. But it is less convenient, and
that really is a consideration.

For instance, this is certainly fine for me:

API.roundCorners(myDiv);

And this is overkill:

if (API.roundCorners) {
API.roundCorners(myDiv);
}

Because rounded corners are merely a nice touch, and not something I
care to make a big deal about in my code.

And while there are times I might appreciate this flexibility:

if (API.myCoolFade) {
API.myCoolFade(myDiv);
} else {
myDiv.style.display = 'none';
}

It's also pretty nice to be able to do this:

API.myCoolFade(myDiv)

and know that the library is internally checking API.canSetOpacity and
whatever other flags it needs, then defaulting to its own
"style.display = 'none'" branch if the effects are not available.

I know that such a technique is less flexible. For instance, I
couldn't choose to do this:

if (API.myCoolFade) {
API.myCoolFade(myDiv);
} else {
var warning = document.createElement("H3");
myDiv.insertBefore(warning, myDiv.firstChild);
for (var i = 0; i < 5; i++) {
setTimeout((function(seconds) {
return function() {
warning.innerHTML = "This div will " +
"self-destruct in " + seconds +
" seconds!";
};
})(5 - i), 1000 * i);
}
setTimeout(function() {
myDiv.style.display = 'none';
}, 5000);
}

but I'm often willing to sacrifice such flexibility for the simplicity
of the static API.

> [ ... ]
> A library could provide a static API and provide a separate mechanism
> for determining browser support of each function, but I don't know
> that that would be advantageous in any way aside from allowing lazily-
> written, terser code.

Of course that last phrase can also be written "simpler, clearer
code". :-)

One technique I've used on several occasions in my own mini-library
code is to add "supported" properties to API functions, which return
values "complete", "degrade", "empty", or false, depending upon
whether the function is completely supported, degrades acceptably,
returns empty objects or arrays, or is totally unsupported, with code
something like this:

API.myCoolFade = API._support((function() {
if (API.opacitySupported) return "complete";
return "degrade";
)(), function(elt) {
if (API.opacitySupported) {
// cool opacity animation here.
} else {
if (elt) elt.style.display = 'none';
}
});

The _support function simply adds the 'supported' property to the
function supplied as the second parameter, with the value supplied in
the first parameter, and returns this enhanced function.

It can then be used simply, if I don't care:

API.roundCorner(myDiv);

Or I can test if I like:

if (API.myCoolFade.supported) {
API.myCoolFade(myDiv);
} else {
myDiv.style.display = 'none'
}

Or if I really want my own alternate degrading technique, I can check
the value of supported:

if (API.myCoolFade.supported == "complete") {
API.myCoolFade(myDiv);
} else if (API.myCoolFade.supported == "degrade") {
// My hand-rolled alternate hide technique here.
} else {
myDiv.style.display = 'none'
}

It has worked for me, but I haven't had to use it much, because it's
never been for large public APIs. It was exactly this sort of pseudo-
fade that motivated it, though, and it worked well enough there. For
API methods that returned arrays of nodes, usually there is complete
support across browsers, but when there isn't, the "supported"
property tells me that the function will at least return me an array I
could continue to process, even if it's empty, which often simplified
further coding.

In any case, I've never tried to code in the dynamic API style for
library code. Are there good examples of libraries that do it? I
understand My Library does; are there other publicly available
examples?

-- Scott

From: David Mark on
Scott Sauyet wrote:
> toby.oconnell(a)gmail.com wrote:
>> Scott Sauyet wrote:
>>
>>> I'm also curious about the dynamic API you present. Obviously that's
>>> one clear way to avoid failing calls to API methods. What are the
>>> advantages over the method that provides a static API that in the
>>> absence of browser support reverts to dummy code that does nothing,
>>> returns empty arrays or false results for any of its calls?
>> Usinging such a static API can keep code from blowing up but it can
>> also obscure API misuse and cause other problems.
>
> It can, and it's also more flexible. But it is less convenient, and
> that really is a consideration.
>
> For instance, this is certainly fine for me:
>
> API.roundCorners(myDiv);
>
> And this is overkill:
>
> if (API.roundCorners) {
> API.roundCorners(myDiv);
> }

No, you do _not_ do it that way. You do a one-time check at the start
for required methods.

>
> Because rounded corners are merely a nice touch, and not something I
> care to make a big deal about in my code.
>
> And while there are times I might appreciate this flexibility:
>
> if (API.myCoolFade) {
> API.myCoolFade(myDiv);
> } else {
> myDiv.style.display = 'none';
> }
>
> It's also pretty nice to be able to do this:
>
> API.myCoolFade(myDiv)

Not at all nice when it blows up or fails silently. ;)

>
> and know that the library is internally checking API.canSetOpacity and
> whatever other flags it needs, then defaulting to its own
> "style.display = 'none'" branch if the effects are not available.

Too much bloat and inefficiency in the internal code.

>
> I know that such a technique is less flexible. For instance, I
> couldn't choose to do this:
>
> if (API.myCoolFade) {
> API.myCoolFade(myDiv);
> } else {
> var warning = document.createElement("H3");
> myDiv.insertBefore(warning, myDiv.firstChild);
> for (var i = 0; i < 5; i++) {
> setTimeout((function(seconds) {
> return function() {
> warning.innerHTML = "This div will " +
> "self-destruct in " + seconds +
> " seconds!";
> };
> })(5 - i), 1000 * i);
> }
> setTimeout(function() {
> myDiv.style.display = 'none';
> }, 5000);
> }
>
> but I'm often willing to sacrifice such flexibility for the simplicity
> of the static API.

But a static API can't abstract a an unknown environment in any sort of
efficient and flexible manner.

>
>> [ ... ]
>> A library could provide a static API and provide a separate mechanism
>> for determining browser support of each function, but I don't know
>> that that would be advantageous in any way aside from allowing lazily-
>> written, terser code.
>
> Of course that last phrase can also be written "simpler, clearer
> code". :-)
>
> One technique I've used on several occasions in my own mini-library
> code is to add "supported" properties to API functions, which return
> values "complete", "degrade", "empty", or false, depending upon
> whether the function is completely supported, degrades acceptably,
> returns empty objects or arrays, or is totally unsupported, with code
> something like this:

Okay, but I don't see why you would need more than a boolean (e.g. works
or not).

>
> API.myCoolFade = API._support((function() {
> if (API.opacitySupported) return "complete";
> return "degrade";
> )(), function(elt) {
> if (API.opacitySupported) {
> // cool opacity animation here.
> } else {
> if (elt) elt.style.display = 'none';
> }
> });

See what I mean about bloat? Imagine an API with thousands of methods
doing something like this for each one. It wouldn't be feasible on the Web.

>
> The _support function simply adds the 'supported' property to the
> function supplied as the second parameter, with the value supplied in
> the first parameter, and returns this enhanced function.
>
> It can then be used simply, if I don't care:
>
> API.roundCorner(myDiv);
>
> Or I can test if I like:
>
> if (API.myCoolFade.supported) {
> API.myCoolFade(myDiv);
> } else {
> myDiv.style.display = 'none'
> }
>
> Or if I really want my own alternate degrading technique, I can check
> the value of supported:
>
> if (API.myCoolFade.supported == "complete") {
> API.myCoolFade(myDiv);
> } else if (API.myCoolFade.supported == "degrade") {
> // My hand-rolled alternate hide technique here.
> } else {
> myDiv.style.display = 'none'
> }

But this is not efficient. A one-off gateway at the start is all you
need. Checking these things each time will bog down your app.

>
> It has worked for me, but I haven't had to use it much, because it's
> never been for large public APIs. It was exactly this sort of pseudo-
> fade that motivated it, though, and it worked well enough there. For
> API methods that returned arrays of nodes, usually there is complete
> support across browsers, but when there isn't, the "supported"
> property tells me that the function will at least return me an array I
> could continue to process, even if it's empty, which often simplified
> further coding.

Yes, for a small Intranet app, you could certainly get by with the above
(depending on its performance requirements of course).

>
> In any case, I've never tried to code in the dynamic API style for
> library code. Are there good examples of libraries that do it? I
> understand My Library does; are there other publicly available
> examples?
>

Not that I know of. :)
From: Garrett Smith on
Peter Michaux wrote:
> On Feb 25, 9:31 pm, David Mark <dmark.cins...(a)gmail.com> wrote:
>> Peter Michaux wrote:
>
[...]

> Some web applications benefit greatly from drag-and-drop
> functionality. They benefit so greatly and the non-drag-and-drop
> version is so bad that the non-drag-and-drop version is never built.
> There are some some web applications that you could say *require*
> drag-and-drop: games, drawing programs. There is no financial
> incentive to building the non-drag-and-drop version. Drag-and-drop in
> a web page doesn't seem to work on my iPhone. So it isn't that the
> decision makers of the web page were "The Crazies". It is actually the
> phone and/or the phone's browser that is not up to the task.
>
Drag'n'drop in iPhone requires a lot of extra effort. Yes the makers of
the iPhone were not up to much tasks other than marketing.

Try changing an iPhone's battery, for example.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Peter Michaux on
On Feb 27, 12:15 am, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:

> Drag'n'drop in iPhone requires a lot of extra effort.

How would drag and drop even work in iPhone's Safari browser? It seems
that gestures are already so heavily used there aren't many gestures
available for drag and drop functionality.


> Yes the makers of
> the iPhone were not up to much tasks other than marketing.

That statement doesn't mean much.


> Try changing an iPhone's battery, for example.

I can see Apple's argument that a user-changable battery requires more
casing/size and so is not desirable. I should, however, be able to
stop at a local Apple store and have the battery changed in a couple
minutes.

Peter
From: David Mark on
Peter Michaux wrote:
> On Feb 27, 12:15 am, Garrett Smith <dhtmlkitc...(a)gmail.com> wrote:
>
>> Drag'n'drop in iPhone requires a lot of extra effort.
>
> How would drag and drop even work in iPhone's Safari browser? It seems
> that gestures are already so heavily used there aren't many gestures
> available for drag and drop functionality.

Ham-fisted. If you can't detect mousemove, bail on DnD. Simple as
that. Trying to bastardize gestures to to DnD is er Crazy. :)