Root Component class from an unreleased UI framework
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var HIDE_CLASS = 'ui-hidden'; | |
var DISABLED_CLASS = 'ui-disabled'; | |
var FOCUSABLE_GRABBER = ':tabbable:visible:first'; | |
ui.component = ui.define({ | |
id: null, | |
cls: null, | |
locator: null, | |
hidden: false, | |
disabled: false, | |
parent: null, | |
components: null, | |
renderTo: null, | |
el: null, | |
bodyEl: null, | |
bodySelector: null, | |
rendered: false, | |
destroyed: false, | |
_componentMap: null, | |
grabbers: null, | |
elements: null, | |
template: '<div id="{{id}}" class="ui-component {{cls}}"></div>', | |
bodyTemplate: null, | |
lazyRender: false, | |
_previousDisplayState: null, | |
type: 'component', | |
EVENTS: { | |
'render': function (/*cmp*/) {}, | |
'afterrender': function (/*cmp*/) {}, | |
'show': function (/*cmp*/) {}, | |
'hide': function (/*cmp*/) {}, | |
'enable': function (/*cmp*/) {}, | |
'disable': function (/*cmp*/) {} | |
}, | |
constructor: function (config) { | |
var components = config && config.components ? config.components : this.components; | |
config && this._applyConfig(config); | |
this.components = {}; | |
this._componentMap = []; | |
if (components) { | |
each(components, function (component) { | |
if (component.config) { | |
this.addComponent(component.type, component.config); | |
} else { | |
this.addComponent(component); | |
} | |
}, this); | |
} | |
this._template = new ui.Template(this.template); | |
merge(config, this, true); | |
ui.manager.register(this); | |
}, | |
getTemplateParams: function() { | |
return { | |
id: this.id || '', | |
cls: this.cls || '' | |
}; | |
}, | |
getTemplatePartials: function() { | |
return {}; | |
}, | |
_bindUIEvents: function() { | |
}, | |
addComponent: function (type, config) { | |
var child; | |
isObject(type) && (child = type); | |
isString(type) && (child = ui.manager.get(type)); | |
!child && (child = new type(config)); | |
child.setParent(this); | |
if (this.rendered) { | |
child.render(); | |
} | |
return child; | |
}, | |
removeComponent: function (component) { | |
delete this.components[component.locator]; | |
removeElement(this._componentMap, component.locator); | |
component.setParent(null); | |
}, | |
destroyComponents: function() { | |
this.eachComponent(function (locator, component) { | |
component.destroy(); | |
}); | |
}, | |
eachComponent: function(callback, scope) { | |
each(this._componentMap, function (locator, index) { | |
return callback.call(scope || this, locator, this.components[locator], index); | |
}, this); | |
}, | |
focus: function() { | |
var target = grab(FOCUSABLE_GRABBER, this.bodyEl); | |
}, | |
_applyConfig: function(config) { | |
if (config.listeners) { | |
each(config.listeners, function (key, value) { | |
if (key !== 'scope') { | |
this.addListener(key, value, config.listeners.scope || this); | |
} | |
}, this); | |
} | |
merge(config, this); | |
delete this.listeners; | |
delete this.components; | |
}, | |
setParent: function(parent) { | |
this.parent = parent; | |
this.parent.registerChild(this); | |
}, | |
registerChild: function(child) { | |
this.components[child.locator] = child; | |
this._componentMap.push(child.locator); | |
}, | |
render: function() { | |
if (this.rendered !== true) { | |
this._beforeRender(); | |
this._renderElement(); | |
this._renderComponents(); | |
this.rendered = true; | |
} | |
if (this.hidden) { | |
this._doHide(); | |
} | |
this._afterRender(); | |
this.fireEvent('afterrender', this); | |
this._bindUIEvents(); | |
}, | |
show: function() { | |
if (this.hidden) { | |
if (!this.rendered && this.parent && this.parent.rendered) { | |
this.render(); | |
} | |
this._doShow(); | |
this.hidden = false; | |
this.fireEvent('show', this); | |
} | |
}, | |
hide: function() { | |
if (!this.hidden) { | |
this._doHide(); | |
this.hidden = true; | |
this.fireEvent('hide', this); | |
} | |
}, | |
_doShow: function() { | |
if (this.rendered) { | |
this.el.classList.remove(HIDE_CLASS); | |
} | |
}, | |
_doHide: function() { | |
if (this.rendered) { | |
this.el.classList.add(HIDE_CLASS); | |
} | |
}, | |
setVisibility: function(visible) { | |
this[visible ? 'show' : 'hide'](); | |
}, | |
enable: function() { | |
if (this.disabled) { | |
this.disabled = false; | |
if (this.rendered) { | |
this.el.classList.remove(DISABLED_CLASS); | |
} | |
this.fireEvent('enable', this); | |
} | |
}, | |
disable: function() { | |
if (!this.disabled) { | |
this.disabled = true; | |
if (this.rendered) { | |
this.el.classList.add(DISABLED_CLASS); | |
} | |
this.fireEvent('disable', this); | |
} | |
}, | |
_beforeRender: function() { | |
}, | |
_renderElement: function() { | |
this.el = this._template.render(this.getTemplateParams(), this.getTemplatePartials()); | |
this.bodyEl = this.el; | |
if (this.bodySelector) { | |
this.bodyEl = grab(this.bodySelector, this.el); | |
} | |
var container = this.parent ? | |
(this.renderTo ? grab(this.renderTo, this.parent.el) : this.parent.bodyEl) : | |
(this.renderTo ? grab(this.renderTo) : document.body); | |
container && container.appendChild(this.el) || document.body.appendChild(this.el); | |
}, | |
_renderComponents: function() { | |
this.eachComponent(function (locator, component) { | |
if (!component.hidden || !this.lazyRender) { | |
component.render(); | |
} | |
}, this); | |
}, | |
_afterRender: function() { | |
this._processGrabbers(); | |
}, | |
_processGrabbers: function() { | |
if (this.grabbers) { | |
this.elements = {}; | |
this._resolveElements(this.grabbers); | |
} | |
}, | |
_resolveElements: function(grabbers) { | |
each(grabbers, function (grabber, name) { | |
if (!own(this.elements, name)) { | |
this.elements[name] = grab(grabber, this.el); | |
} | |
}, this) | |
}, | |
destroy: function () { | |
if (!this.destroyed) { | |
if (this.parent) { | |
this.parent.removeComponents(this); | |
} | |
this._removeEl(); | |
this.destroyComponents(); | |
this.purgeListeners(); | |
this.destroyed = true; | |
this.el = null; | |
this.bodyEl = null; | |
this.elements = null; | |
this.component = null; | |
this._componentMap = null; | |
ui.manager.unregister(this); | |
} | |
}, | |
_removeEl: function () { | |
if (this.rendered) { | |
this.el.parentNode.removeChild(this.el); | |
} | |
this.el = null; | |
this.elements = null; | |
this.rendered = false; | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment