New DOM event types

Hi gentlemen.

We at Opera have had some demands to find ways that will allow a webpage
to control zooming or panning/scrolling, specially on mobiles. The typical
use case are map applications on devices, where the user double taps or
drags the viewport around to zoom and pan, although the map should have
the chance to detect these events and apply them on the map instead.
Dragging overlaid objects in the page is also another use case.

Subject of work, the DOM 3 Level Events spec
http://www.w3.org/TR/DOM-Level-3-Events/
http://dev.w3.org/2006/webapi/DOM-Level-3-Events/html/DOM3-Events.html

First case: scrolling.

The specification already specifies the 'scroll' event, which is not
synchronized with the scrolling action, and not cancelable, being
therefore only useful as a notification. We need a type of scroll event
which would be synchronized with the scrolling action, and if prevented
would prevent the scrolling entirely. The event can be called
'beforescroll'. The scroll event needs both a deltaX and deltaY with the
amount of pixels by with he user agent will scroll as consequence of
diagonal scroll/pan. Unfortunately, .detail is not enough.

So, to summarize:
    - new event type 'beforescroll', fired before any scrolling action,
cancelable
    - probably a new interface derived from Event, which has the deltaX and
deltaY, like ScrollEvent, or extending that information in UIEvent

Second case: zooming

There are no references to zooming or zoom events in the specification,
but there is a magnify event on the developer working draft. Ideally, we
should have both a 'beforemagnify' event, like 'beforescroll', cancelable
and synchronized with the zooming action, and an 'aftermagnify', not
cancelable, and not synchronized with the zooming action. Given that
zooming is a viewport action, UIEvent.detail should be good enough to give
the *new* zoom level that the user agent will apply to the viewport. The
detail property would contain an integer with the zoom level in
percentage, meaning 100 would be the default zoom level. However, it would
be useful to have the *current* zoom level available in a global property,
like window.zoomLevel, but that is out of scope of this specification.

Handling the target would be similar to the scroll event. In case the
zooming action is performed by a pointing device on top of an element,
like mousewheel when scrolling, the target of the event is the element
beneath the pointing device. Typical examples: pinching on a touch screen,
double tapping on devices, ctrl+mousewheel on desktop computer. If the
zoom action is triggered by other means, and therefore is not "caught"
by the element beneath the pointing device, then the target is the
document.

To summarize:
    - new event type 'beforemagnify', fired before any scrolling action,
cancelable
    - new event type 'magnify', fired after any scrolling action, not
cancelable, doesn't bubble. (It's in the WD)
    - UIEvent.detail has the new zoom level applied o the viewport
    - Event.target set to element below cursor, or document if a pointing
device was not used

Whether beforescroll and beforemagnify buble or not is debatable.
Typically, non-cancelable events aren't while cancelable ones are. I
don't have very strong feelings about this one.

Problem: what happens if a script triggers scrolling, like changing
styles which cause a scrollable container to scroll, assigning
location.hash to a new fragment identifier, or assigning scrollTop on a
scrollable container? Possible answer: the beforescroll and before
magnify events should only be fired in response to user input, and not
scripting. The scripts themselves can know if the page is going to
scroll in advance and make all proper provisions. User input includes
dragging scrollbars, PgUp, PgDown, arrow keys (mobiles and pcs), spatial
navigation, finger swiping, clicking link with fragment identifier, etc...

Theoretical problem: the synchronous cancelable events can introduce
scrolling, or zooming lag. Unfortunately, this is by design as the
scripting environment *needs* to invoke all listeners. To minimize this
problem, the events don't bubble (naturally), and there are the events
that fire *after* the action, just in case the webpage only needs a
notification.

People usually confuse low level mouse events with these actions. Zooming
and scrolling are high level UI actions, which can be triggered in many
other means than just the mouse. Please do not confuse them.

Whether you consider giving the webpage control over these events an
annoyance or not, that is a user agent usability problem. Ask for a
configuration option from your favorite vendor :)

Thoughts ?

Thank you o/

Received on Wednesday, 17 March 2010 00:47:29 UTC