Wow, gigantor mail!

High level response .... I think you're on the right track. I
appreciate how you've laid out all the various considerations, and I
think that you are making the right tradeoffs.

This doesn't mean I won't have minor API nitpickery later, but I think
I'll have to try using it a bit to get that far.

On Thu, Oct 30, 2008 at 2:34 AM, Nigel Tao <[EMAIL PROTECTED]> wrote:
> Relationship to HTML5.
> We're obviously influenced by the HTML5 drag and drop specification
> [#2], but we have deviated from that in several ways.
>
> This is partly because, in Gears, files' contents map to Blob objects,
> which have no HTML5 counterpart. The nearest thing, I think, is a
> string URL like "file:///home/user/foo.txt", but such a string can be
> constructed by arbitrary web apps, and does not indicate an explicit
> user action to grant read permission of certain files to the web app.
>
> A second reason is practical - we are constrained to work with
> existing browsers as shipped, whereas, if I understand correctly,
> HTML5 is an ideal for future browser releases to aim for. For example,
> the ideal, HTML5-inspired API might look like
> event.dataTransfer.getData("application/octet-stream") to get file
> (i.e. binary) data, but we (as a mere browser extension / plug-in) may
> not be able to modify, wrap or otherwise impersonate the native
> DataTransfer object consistently across all Gears platforms.
>
> Finally, we hope to be consistent with the existing desktop.openFiles
> API, and specifically its File interface [#3].

All important considerations. Makes sense.

> API.
> This section describes the API as currently implemented, but I am open
> to alternative designs.
>
> We are maintaining an example drag-and-drop using web page inside the
> Gears repository, at trunk/gears/test/manual/drag_and_drop.html [#4].
> The key API call is
>  desktop.registerDropTarget(domElement, options);
> which causes JavaScript callbacks, as given in the options object
> (i.e. a key/value map), to fire upon DnD events. For example, options
> might have been defined previously as:
>  var options = {};
>  options.ondragenter = function(context) {
>    alert('Got dragenter');
>    return false;
>  };
>
> An alternative suggestion, which is growing on me, is to eliminate the
> options argument entirely and instead set properties on a DropTarget
> object like so:
>  var dropTarget = desktop.registerDropTarget(domElement);
>  dropTarget.ondragenter = function(context) {
>    alert('Got dragenter');
>    return false;
>  };
> This does mean that such properties are modifiable after construction
> of the dropTarget object, and modifiable while handling a DnD event,
> but apart from requiring a little more care in implementation, I think
> that this is a nice feature, on balance.

I like the idea of modifying the drop target directly.

> However, if we decide to make
> the dropTarget object also a DOM element, then we might have the Gears
> event handler and the DOM event handler have the same name - which
> might be a good thing or a bad thing.

I don't like the idea of potential conflicts with standard DOM APIs.

>  var registration = desktop.registerDropTarget(...);
>  // ... do some other stuff ...
>  registration.unregisterDropTarget();
> The current name (unregisterDropTarget) is unwieldy, and may change to
> unregisterSelf(), unregister(), deregister(), or simply cancel(),

Agree the name is unwieldy, but don't have a preference as to the
proposed alternatives.

> Similarly, the registerDropTarget name is not set in stone, and other
> candidates include addDropTarget and createDropTarget. Furthermore,
> the "DropTarget" name could become "DragAndDropElement" or
> "DragAndDropParticipant" if we don't see the need to distinguish
> separate functions to register / add / create a DropTarget and a
> DragSource (although we have no immediate plans to implement
> DragSources).

No huge preference. This may change when I play with it a bit.

> Another item for consideration is whether or not the function should
> modify the existing DOM element (that is passed as an argument to
> registerDropTarget), or create a new element that is a child of that
> given element.

I didn't get this part. From the code reviews, it doesn't appear that
you are modifying the DOM in any script-visible way. I think this is
important. It would be weird to add properties or children.

> Anyway, back to the API. I previously mentioned specifying a callback
> that takes one argument, the "context".
>  options.ondragenter = function(context) { alert('Got dragenter'); };
> The context is a JavaScript object with named properties. For example,
> during ondrop (but not during ondragenter, ondragover or ondragleave),
> context.files will contain an array of File objects, exactly like the
> array of Files returned by desktop.openFiles. Another property is
> context.event, which contains the browser-supplied event object (and
> therefore things like context.event.clientX and context.event.clientY,
> and modifier key state such as context.event.shiftKey) under a
> consistent name (as opposed to, say, window.event, which not all
> current browsers support).

It might be OK to pass the native browser event as a separate
parameter from the context, just to simplify (this part of the code is
a bit hairy).

Also, the name 'context' doesn't really work in this, err, context,
for me. Maybe 'event' and 'browserEvent'? Or just 'dragData'. Not a
big deal.

> Other properties that we intend to
> implement are, when dragging files, the number of files, their total
> size in bytes, and their file extensions and best-guessed MIME types,
> so that, for example, a YouTube movie uploader web page can provide
> graphical feedback, before the drop, if a user tries to drop a Word
> document onto the page, or a file that is too large to accept. One
> undecided API feature is whether or not the caller of
> registerDropTarget has to explicitly register their interest in what
> context attributes that they want - since not every web-app may care
> about MIME types (and providing that information may require disk
> I/O). Such an interest might look like this
>  options.contextAttributes = [ 'event', 'fileArray', 'fileMimeTypes' ];
>  desktop.registerDropTarget(domElement, options);

It would be better to not have to register such interest. How much
extra IO is it to determine them? Can we do it asynchronously and just
not fire any events until we have the data?

> An earlier iteration of the API provided the event itself as the
> callback's sole argument, as per the HTML5 spec ("When an event
> handler attribute is invoked, its argument must be set to the Event
> object of the event in question" at [#5]), i.e. it was
>  options.ondragenter = function(event) {
>    alert(event.clientX);
>    alert(event.files.length);
>    return false;
>  };
> instead of
>  options.ondragenter = function(context) {
>    alert(context.event.clientX);
>    alert(context.files.length);
>    return false;
>  };
> however, the first approach required adding named attributes (e.g. the
> files array) to the existing event object, which might cause a
> collision if future browser versions ever add a similarly named
> attribute to their native event object. The current implementation
> provides Gears' extra information (such as the files array) as
> siblings of the event object, under a parent "context" object, rather
> than as children of the event object itself, which avoids any
> unforseen consequences of modifying the browser's native event object.
> While I favor the second, current, approach, I still could be
> convinced to go with the earlier approach, since it is more like what
> HTML5 specifies.

I agree with the chain of decisions that led to the current design.

> The various callbacks (ondragenter, ondragover, ondragleave, ondrop)
> should return false if they wish to accept the drag operation. This
> may seem counter-intuitive to the usual programming convention that a
> callback returns a boolean indicating success, but this is mimicking
> the HTML5 idea that an event handler returns false to prevent the
> default action, which in this case would be to navigate to the given
> file (and away from the web app that wants the file drop). Note that
> the JavaScript callback does not have to explicitly call
> context.event.preventDefault().

Couple points here:

* Returning false to ondragleave to accept the drag seems weird to me.
Why would anyone want to wait for ondragleave to accept the drag?
Similarly, returning false to ondragenter, ondragover, etc seems
meaningless to me.

* I see nothing weird about returning false to 'accept' the drag. I
think of it less like 'accepting' (since that is kinda meaningless
with this API -- there's nothing to accept, you have already gotten
all the data in ondragdrop) and more like preventing the navigation
which would normally occur on drop.



- a

Reply via email to