// Copyright (c) 2009-2012 Techinox Information Technologies (http://www.techinox.com)
// Techinox Commercial License
//
// @author Armagan Amcalar <armagan.amcalar@tart.com.tr>
goog.provide('tart.ui.ComponentManager');
goog.require('tart.events');
goog.require('goog.array');
goog.require('goog.events.EventType');
goog.require('tart.events.HoverHandler');
goog.require('tart.events.GestureHandler');
/**
* @fileoverview Registry for tart.ui.DlgComponent. Manages DOM event interactions for these components.
*/
/**
*
* @constructor
*/
tart.ui.ComponentManager = function() {
/** @type {Object.<string, tart.ui.DlgComponent>} */
this.components = {};
this.gestureHandler = tart.events.GestureHandler.getInstance();
this.hoverHandler = new tart.events.HoverHandler();
goog.events.listen(document.body, tart.ui.ComponentManager.eventTypes, this);
goog.events.listen(this.hoverHandler, [tart.events.EventType.MOUSEENTER, tart.events.EventType.MOUSELEAVE], this);
};
goog.addSingletonGetter(tart.ui.ComponentManager);
/**
* Returns parent components (if available) of a given DOM node.
*
*
* @param {Node} child DOM node that will be used for finding parent components.
* @return {Array.<tart.ui.DlgComponent>} Parent components.
*/
tart.ui.ComponentManager.prototype.getParentComponents = function(child) {
var node = child, cmps = [], cmp, ids;
if (ids = node.getAttribute && node.getAttribute('data-cmp')) {
ids.split(',').forEach(function(id) {
if (id) cmps.push(this.components[id]);
}, this);
return cmps;
}
ids = [];
do {
if (cmp = this.components[node.id]) {
cmps.push(cmp);
ids.push(node.id);
}
} while (node = node.parentNode);
child.setAttribute('data-cmp', ids.join(','));
return cmps;
};
/**
* Keeps event types.
* @type {Array.<goog.events.EventType>}
*/
tart.ui.ComponentManager.eventTypes = [
goog.events.EventType.CLICK,
goog.events.EventType.MOUSEOVER,
goog.events.EventType.MOUSEOUT,
goog.events.EventType.MOUSEMOVE,
goog.events.EventType.MOUSEDOWN,
goog.events.EventType.MOUSEUP,
tart.events.EventType.MOUSEENTER,
tart.events.EventType.MOUSELEAVE,
tart.events.EventType.TAP,
tart.events.EventType.SWIPE_LEFT,
tart.events.EventType.SWIPE_RIGHT,
tart.events.EventType.SWIPE_UP,
tart.events.EventType.SWIPE_DOWN,
goog.events.EventType.SCROLL,
goog.events.EventType.KEYUP,
goog.events.EventType.KEYPRESS,
goog.events.EventType.FOCUSIN,
goog.events.EventType.FOCUSOUT,
goog.events.EventType.TOUCHSTART,
goog.events.EventType.TOUCHMOVE,
goog.events.EventType.TOUCHEND
];
/**
* @param {goog.events.BrowserEvent} e Browser event to be executed.
*/
tart.ui.ComponentManager.prototype.handleEvent = function (e) {
var cmps = this.getParentComponents(e.target),
broken = false;
do {
if (broken) break;
if (e.type == tart.events.EventType.MOUSEENTER || e.type == tart.events.EventType.MOUSELEAVE) {
if (e.relatedTarget && !goog.dom.contains(e.target, e.relatedTarget)) {
broken = this.callHandlers_(cmps, e);
}
}
else {
broken = this.callHandlers_(cmps, e);
}
} while (e.target = e.target.parentNode);
};
/**
* Given a list of components, checks whether any component would respond to the given event and if so, executes the
* event handler defined in the component.
*
* @private
*
* @param {Array.<tart.ui.DlgComponent>} cmps Array of components to look for handlers about the event's target.
* @param {goog.events.BrowserEvent} e Browser event that will be executed for the target.
*/
tart.ui.ComponentManager.prototype.callHandlers_ = function(cmps, e) {
var broken = false;
for (var i = 0; i < cmps.length; i++) {
var cmp = cmps[i];
var handlers = cmp && cmp.events && cmp.events[e.type];
if (!handlers) continue;
var selectors = goog.object.getKeys(handlers);
if (this.callHandler_(cmp, e, handlers, selectors) === false) {
broken = true;
break;
}
}
return broken;
};
/**
* @private
*
* @param cmp
* @param e
* @param handlers
* @param selectors
* @return {boolean}
*/
tart.ui.ComponentManager.prototype.callHandler_ = function(cmp, e, handlers, selectors){
var rv = true;
goog.array.forEach(selectors, function(selector) {
// event's target equals to handler's selector
if (this.matchesSelector(e.target, selector)) {
rv = handlers[selector].call(cmp, e);
}
}, this);
return rv;
};
/**
*
* @param el
* @param selector
* @return {*}
*/
tart.ui.ComponentManager.prototype.matchesSelector = function(el, selector) {
return goog.array.indexOf(document.querySelectorAll(selector), el) >= 0;
};
/**
* Set given component.
* @param {tart.ui.DlgComponent} cmp Component which will be set to components.
*/
tart.ui.ComponentManager.prototype.set = function(cmp) {
this.components[cmp.getId()] = cmp;
};
/**
* Removes given component.
* @param {tart.ui.DlgComponent} cmp Component which will be removed from components.
*/
tart.ui.ComponentManager.prototype.remove = function(cmp) {
delete this.components[cmp.getId()];
};