Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 46 additions & 9 deletions dom-renderables/DOMElement.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,17 +288,17 @@ DOMElement.prototype.onOpacityChange = function onOpacityChange(opacity) {
* Method to be invoked by the node as soon as a new UIEvent is being added.
* This results into an `ADD_EVENT_LISTENER` command being sent.
*
* @param {String} UIEvent UIEvent to be subscribed to (e.g. `click`)
* @param {String} uiEvent uiEvent to be subscribed to (e.g. `click`)
*
* @return {undefined} undefined
*/
DOMElement.prototype.onAddUIEvent = function onAddUIEvent(UIEvent) {
if (this._UIEvents.indexOf(UIEvent) === -1) {
this._subscribe(UIEvent);
this._UIEvents.push(UIEvent);
DOMElement.prototype.onAddUIEvent = function onAddUIEvent(uiEvent) {
if (this._UIEvents.indexOf(uiEvent) === -1) {
this._subscribe(uiEvent);
this._UIEvents.push(uiEvent);
}
else if (this._inDraw) {
this._subscribe(UIEvent);
this._subscribe(uiEvent);
}
return this;
};
Expand All @@ -309,13 +309,50 @@ DOMElement.prototype.onAddUIEvent = function onAddUIEvent(UIEvent) {
* @method
* @private
*
* @param {String} UIEvent Event type (e.g. `click`)
* @param {String} uiEvent Event type (e.g. `click`)
*
* @return {undefined} undefined
*/
DOMElement.prototype._subscribe = function _subscribe (UIEvent) {
DOMElement.prototype._subscribe = function _subscribe (uiEvent) {
if (this._initialized) {
this._changeQueue.push('SUBSCRIBE', UIEvent, true);
this._changeQueue.push('SUBSCRIBE', uiEvent);
}
if (!this._requestingUpdate) this._requestUpdate();
};

/**
* When running in a worker, the browser's default action for specific events
* can't be prevented on a case by case basis (via `e.preventDefault()`).
* Instead this function should be used to register an event to be prevented by
* default.
*
* @method
*
* @param {String} uiEvent UI Event (e.g. wheel) for which to prevent the
* browser's default action (e.g. form submission,
* scrolling)
* @return {undefined} undefined
*/
DOMElement.prototype.preventDefault = function preventDefault (uiEvent) {
if (this._initialized) {
this._changeQueue.push('PREVENT_DEFAULT', uiEvent);
}
if (!this._requestingUpdate) this._requestUpdate();
};

/**
* Opposite of {@link DOMElement#preventDefault}. No longer prevent the
* browser's default action on subsequent events of this type.
*
* @method
*
* @param {type} uiEvent UI Event previously registered using
* {@link DOMElement#preventDefault}.
* @return {undefined} undefined
*/
DOMElement.prototype.allowDefault = function allowDefault (uiEvent) {
if (this._initialized) {
this._changeQueue.push('ALLOW_DEFAULT', uiEvent);
}
if (!this._requestingUpdate) this._requestUpdate();
};
Expand Down
86 changes: 75 additions & 11 deletions dom-renderers/DOMRenderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,80 @@ function DOMRenderer (element, selector, compositor) {
*
* @return {undefined} undefined
*/
DOMRenderer.prototype.subscribe = function subscribe(type, preventDefault) {
// TODO preventDefault should be a separate command
DOMRenderer.prototype.subscribe = function subscribe(type) {
this._assertTargetLoaded();

this._target.preventDefault[type] = preventDefault;
this._listen(type);
this._target.subscribe[type] = true;
};

/**
* Unsubscribes from all events that are of the specified type.
*
* @method
*
* @param {String} type Event type to unsubscribe from.
* @return {undefined} undefined
*/
DOMRenderer.prototype.unsubscribe = function unsubscribe(type) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs docs

this._assertTargetLoaded();
this._listen(type);
this._target.subscribe[type] = false;
};

/**
* Used to preventDefault if an event of the specified type is being emitted on
* the currently loaded target.
*
* @method
*
* @param {String} type The type of events that should be prevented.
* @return {undefined} undefined
*/
DOMRenderer.prototype.preventDefault = function preventDefault(type) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs docs

this._assertTargetLoaded();
this._listen(type);
this._target.preventDefault[type] = true;
};

/**
* Used to undo a previous call to preventDefault. No longer `preventDefault`
* for this event on the loaded target.
*
* @method
* @private
*
* @param {String} type The event type that should no longer be affected by
* `preventDefault`.
* @return {undefined} undefined
*/
DOMRenderer.prototype.allowDefault = function allowDefault(type) {
this._assertTargetLoaded();
this._listen(type);
this._target.preventDefault[type] = false;
};

/**
* Internal helper function used for adding an event listener for the the
* currently loaded ElementCache.
*
* If the event can be delegated as specified in the {@link EventMap}, the
* bound {@link _triggerEvent} function will be added as a listener on the
* root element. Otherwise, the listener will be added directly to the target
* element.
*
* @private
* @method
*
* @param {String} type The event type to listen to (e.g. click).
* @return {undefined} undefined
*/
DOMRenderer.prototype._listen = function _listen(type) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needs docs

this._assertTargetLoaded();

if (
!this._target.listeners[type] && !this._root.listeners[type]
) {
// FIXME Add to content DIV if available
var target = eventMap[type][1] ? this._root : this._target;
target.listeners[type] = this._boundTriggerEvent;
target.element.addEventListener(type, this._boundTriggerEvent);
Expand Down Expand Up @@ -143,18 +207,18 @@ DOMRenderer.prototype._triggerEvent = function _triggerEvent(ev) {
var path = evPath[i].dataset.faPath;
if (!path) continue;

// Optionally preventDefault. This needs forther consideration and
// should be optional. Eventually this should be a separate command/
// method.
if (this._elements[path].preventDefault[ev.type]) {
ev.preventDefault();
}

// Stop further event propogation and path traversal as soon as the
// first ElementCache subscribing for the emitted event has been found.
if (this._elements[path] && this._elements[path].subscribe[ev.type]) {
ev.stopPropagation();

// Optionally preventDefault. This needs forther consideration and
// should be optional. Eventually this should be a separate command/
// method.
if (this._elements[path].preventDefault[ev.type]) {
ev.preventDefault();
}

var NormalizedEventConstructor = eventMap[ev.type][0];

// Finally send the event to the Worker Thread through the
Expand Down
17 changes: 16 additions & 1 deletion renderers/Context.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,22 @@ Context.prototype.receive = function receive(path, commands, iterator) {

case 'SUBSCRIBE':
if (this.WebGLRenderer) this.WebGLRenderer.getOrSetCutout(path);
this.DOMRenderer.subscribe(commands[++localIterator], commands[++localIterator]);
this.DOMRenderer.subscribe(commands[++localIterator]);
break;

case 'UNSUBSCRIBE':
if (this.WebGLRenderer) this.WebGLRenderer.getOrSetCutout(path);
this.DOMRenderer.unsubscribe(commands[++localIterator]);
break;

case 'PREVENT_DEFAULT':
if (this.WebGLRenderer) this.WebGLRenderer.getOrSetCutout(path);
this.DOMRenderer.preventDefault(commands[++localIterator]);
break;

case 'ALLOW_DEFAULT':
if (this.WebGLRenderer) this.WebGLRenderer.getOrSetCutout(path);
this.DOMRenderer.allowDefault(commands[++localIterator]);
break;

case 'GL_SET_DRAW_OPTIONS':
Expand Down