Skip to content

Instantly share code, notes, and snippets.

@av
Created August 26, 2020 09:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save av/dabdff40d6c620edec5cf12c5213a31a to your computer and use it in GitHub Desktop.
Save av/dabdff40d6c620edec5cf12c5213a31a to your computer and use it in GitHub Desktop.
Root Component class from an unreleased UI framework
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