este-library-oldschool
Version:
Library for github.com/steida/este.git
288 lines (268 loc) • 8.79 kB
JavaScript
// Generated by github.com/steida/coffee2closure 900.1.18
/**
@fileoverview este.ui.Component provides easy event delegation and synthetic
events registration. For example, if you want to use bubbling focus/blur, you
have to instantiate goog.events.FocusHandler in enterDocument method, and
dispose it in exitDocument. With este.ui.Component, you don't have to write
this boilerplate code. For easy event delegation, replace event src with
matching string selector. Note how bindModel method is used for automatic
element-model wiring via 'e-model-cid' attribute.
Supported synthetic (with bubbling) events:
- tap, swipeleft, swiperight, swipeup, swipedown
- focusin, focusout
- input
- submit
- key or number from goog.events.KeyCodes enumeration
Examples:
```coffee
this.enterDocument ->
super()
this.on this.getElement(), 'click', this.onClick
this.on '.box', 'tap', this.onBoxTap
this.on 'input', 'focusin', this.onInputFocus
this.on this.boxElement, 'tap', this.onTap
this.on '.button', 'swipeleft', this.onButtonSwipeleft
this.on '#new-todo-form', 'submit', this.onNewTodoFormSubmit
this.on '.toggle', 'dblclick', this.onToggleDblclick
this.on '.new-post', goog.events.KeyCodes.ENTER, this.onNewCommentKeyEnter
return
```
```coffee
this.enterDocument ->
super()
* note how bindModel is used
this.on '.box', 'tap', this.bindModel this.onBoxTap
return
```
@see /demos/ui/component.html
@see /demos/app/todomvc/js/todos/list/view.coffee
*/
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.superClass_ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
goog.provide('este.ui.Component');
goog.require('este.Collection');
goog.require('este.dom');
goog.require('este.events.EventHandler');
goog.require('este.Model');
goog.require('goog.asserts');
goog.require('goog.dom.classlist');
goog.require('goog.ui.Component');
/**
@param {goog.dom.DomHelper=} domHelper Optional DOM helper.
@constructor
@extends {goog.ui.Component}
*/
este.ui.Component = function(domHelper) {
este.ui.Component.superClass_.constructor.call(this, domHelper);
}
extend(este.ui.Component, superClass);
/**
@param {Function} fn
@param {number} keyCode
@param {*} handler
@return {Function}
@protected
*/
este.ui.Component.wrapListenerForKeyHandlerKeyFilter = function(fn, keyCode, handler) {
return function(e) {
if (e.keyCode !== keyCode) {
return;
}
return fn.call(handler, e);
};
};
/**
@param {Function} fn
@param {string} selector
@return {Function}
@protected
*/
este.ui.Component.wrapListenerForEventDelegation = function(fn, selector) {
var matcher;
matcher = function(node) {
return goog.dom.isElement(node) && este.dom.match(node, selector);
};
return function(e) {
var target;
target = goog.dom.getAncestor(e.target, matcher, true);
if (!target || este.dom.isMouseHoverEventWithinElement(e, target)) {
return;
}
e.originalTarget = e.target;
e.target = target;
return fn.call(this, e);
};
};
/**
@param {Element} el
@return {Element}
@protected
*/
este.ui.Component.getParentElementWithClientId = function(el) {
var parent;
parent = goog.dom.getAncestor(el, function(node) {
return goog.dom.isElement(node) && (node.hasAttribute('e-model-cid') || node.hasAttribute('data-e-model-cid'));
}, true);
return /** @type {Element} */(parent);
};
/**
@type {este.events.EventHandler}
@private
*/
este.ui.Component.prototype.esteHandler_ = null;
/**
@type {Object}
@private
*/
este.ui.Component.prototype.componentListenables_ = null;
/**
@param {goog.events.ListenableType|string} src Event source.
@param {string|number|Array.<string|number>} type Event type to listen for
or array of event types.
@param {Function} fn Optional callback function to be used as the listener.
@param {boolean=} capture Optional whether to use capture phase.
@param {boolean=} once
@protected
*/
este.ui.Component.prototype.on = function(src, type, fn, capture, once) {
var i, id, isKeyEventType, keyCode, len, ref, selector, t, useEventDelegation;
if (goog.isArray(type)) {
for (i = 0, len = type.length; i < len; i++) {
t = type[i];
this.on(src, t, fn, capture);
}
return;
}
id = this.getComponentListenableId(src, type, fn, capture);
if ((ref = this.componentListenables_) != null ? ref[id] : void 0) {
return;
}
if (once) {
fn = (function(src, type, fn, capture) {
return function(e) {
this.off(src, type, fn, capture);
return fn.call(this, e);
};
})(src, type, fn, capture);
}
useEventDelegation = goog.isString(src);
if (useEventDelegation) {
selector = src;
src = this.getElement();
}
isKeyEventType = goog.dom.isElement(src) && goog.isNumber(type);
if (isKeyEventType) {
keyCode = /** @type {number} */(type);
fn = este.ui.Component.wrapListenerForKeyHandlerKeyFilter(fn, keyCode, this);
type = 'key';
}
if (useEventDelegation) {
selector = /** @type {string} */(selector);
fn = este.ui.Component.wrapListenerForEventDelegation(fn, selector);
}
if (this.componentListenables_ == null) {
this.componentListenables_ = {};
}
this.componentListenables_[id] = [src, type, fn, capture];
type = /** @type {string} */(type);
src = /** @type {goog.events.ListenableType} */(src);
this.getHandler().listen(src, type, fn, capture);
};
/**
@param {goog.events.ListenableType|string} src Event source.
@param {string|number|Array.<string|number>} type Event type to listen for
or array of event types.
@param {Function} fn Optional callback function to be used as the listener.
@param {boolean=} capture Optional whether to use capture phase.
@protected
*/
este.ui.Component.prototype.once = function(src, type, fn, capture) {
return this.on(src, type, fn, capture, true);
};
/**
@param {goog.events.ListenableType|string} src Event source.
@param {string|number|Array.<string|number>} type Event type to listen for
or array of event types.
@param {Function} fn Optional callback function to be used as the listener.
@param {boolean=} capture Optional whether to use capture phase.
@protected
*/
este.ui.Component.prototype.off = function(src, type, fn, capture) {
var i, id, len, listenable, ref, t;
if (goog.isArray(type)) {
for (i = 0, len = type.length; i < len; i++) {
t = type[i];
this.off(src, t, fn, capture);
}
return;
}
id = this.getComponentListenableId(src, type, fn, capture);
listenable = (ref = this.componentListenables_) != null ? ref[id] : void 0;
if (!listenable) {
return;
}
this.getHandler().unlisten.apply(this.getHandler(), listenable);
delete this.componentListenables_[id];
};
/**
@override
*/
este.ui.Component.prototype.getHandler = function() {
return this.esteHandler_ != null ? this.esteHandler_ : this.esteHandler_ = new este.events.EventHandler(this);
};
/**
@protected
*/
este.ui.Component.prototype.getComponentListenableId = function(src, type, fn, capture) {
return [goog.isString(src) ? src : goog.getUid(src), type, goog.getUid(fn), capture].join();
};
/**
@override
*/
este.ui.Component.prototype.exitDocument = function() {
var ref;
if ((ref = this.esteHandler_) != null) {
ref.removeAll();
}
this.componentListenables_ = null;
este.ui.Component.superClass_.exitDocument.call(this);
};
/**
Use this method when target has e-model-cid attribute. It will pass model
instead of element if such model exists on any collection on this instance.
@param {Function} fn
@return {Function}
*/
este.ui.Component.prototype.bindModel = function(fn) {
return function(e) {
var cid, el, model;
el = este.ui.Component.getParentElementWithClientId(e.target);
if (el) {
cid = el.getAttribute('e-model-cid') || el.getAttribute('data-e-model-cid');
model = this.findModelOnInstanceByClientId(cid);
}
return fn.call(this, model, el, e);
};
};
/**
@param {string} clientId
@return {este.Model}
@protected
*/
este.ui.Component.prototype.findModelOnInstanceByClientId = function(clientId) {
var key, model, value;
for (key in this) {
value = this[key];
if (value instanceof este.Collection) {
model = value.findByClientId(clientId);
if (model) {
return model;
}
} else if (value instanceof este.Model) {
if (value.get('_cid') === clientId) {
return value;
}
}
}
return null;
};