/**
* 生命周期控制器
*
* @file 核心控制器
* @author Brian Li(lbxxlht@163.com)
* 1.负责UI的生命周期
* 2.提供所有UI都可以使用的公共方法
* 3.扩展控件实例的属性,支持setter和getter
*/
var define = typeof define === 'function' && define.amd ? define : function (factory) {
typeof module === 'object' ? (module.exports = factory(require)) : '';
};
define(function (require) {
var core = require('./core');
var util = require('./util');
// public /////////////////////////////////////////////////////////////////
/**
* 构造函数
*
* @constructor
* @param {Object} param 初始化对象
*/
function Controller(param) {
param = param || {};
param.uitype = util.getFunctionName(this.constructor).toLowerCase();
param.uuid = util.uuid();
this._format();
this.initialize(param);
defineProperties(this);
this.isLoaded = true;
}
Controller.prototype = core;
/**
* 初始化
*
* @param {Object} param Controller初始化对象
* @param {string} param.uuid 自动生成的唯一id
* @param {string} param.uitype ui类型
* @param {string} param.skin 皮肤名称
* @param {HTMLElement | string} param.container root容器的DOM对象或id
* @param {Array<string> | string} param.tpl tpl模板
* @param {Object} param.datasource 数据源
* @param {Object} param.events 注册root容器的事件hash
*/
Controller.prototype.initialize = function (param) {
this.initialParameter = param;
this.uuid = param.uuid;
this.uitype = param.uitype;
this.uiid = param.id;
setupContainer(this, param);
setupPlugin(this, param);
setupSkin(this, param);
setupEvent(this, param);
Eif (param.hasOwnProperty('tpl')) {
this.tpl = param.tpl;
}
Eif (param.hasOwnProperty('datasource')) {
this.datasource = param.datasource;
}
this.render();
};
/**
* 渲染
*/
Controller.prototype.render = function () {
Eif (!util.isDOM(this.container)) {
return;
}
var dataset = util.getDataset(this.container);
// 已在服务端渲染,凡是服务端渲染的认为是非潜逃元素
if (dataset.rendered === 'rendered') {
this.container.attributes.removeNamedItem('data-rendered');
return;
}
else {
if (this.html.length > 0) {
this.container.innerHTML = this.html;
}
}
// 通知所有插件宿主已重绘
for (var key in this.plugin) {
if (typeof this.plugin[key].hostRendered === 'function') {
this.plugin[key].hostRendered();
}
}
this.fire('rendered');
};
/**
* 销毁
*/
Controller.prototype.dispose = function () {
Iif (util.isDOM(this.container)) {
// 销毁内容
if (this.html.length > 0) {
this.container.innerHTML = '';
}
// 销毁事件
removeEventHandlers(this.container, this._temp.events);
// 销毁样式
var className = this._temp.className;
var allClass = this.container.className;
allClass = allClass.replace(' ' + className, '').replace(className, '');
this.container.className = allClass;
}
// 销毁数据结构
this._dispose();
/* eslint-disable */
for (var key in this) {delete this[key];}
/* eslint-enable */
};
// private ///////////////////////////////////////////////////////
/**
* 装载容器
*
* @param {Object} me Controller对象实例
* @param {Object} param Controller初始化对象
*/
function setupContainer(me, param) {
me.container = null;
Eif (util.inNode() || !param.hasOwnProperty('container')) {
return;
}
if (util.isDOM(param.container)) {
me.container = param.container;
return;
}
if (typeof param.container === 'string') {
me.container = document.getElementById(param.container);
return;
}
}
/**
* 初始化插件
*
* @param {Object} me Controller对象实例
* @param {Object} param Controller初始化对象
*/
function setupPlugin(me, param) {
if (!param.hasOwnProperty('plugin') || !(param.plugin instanceof Array) || param.plugin.length === 0) {
return;
}
var plugins = {};
for (var n = 0; n < param.plugin.length; n++) {
var plugin = param.plugin[n];
// 检查依赖
if (plugin.hasOwnProperty('required') && plugin.required instanceof Array && plugin.required.length > 0) {
var checked = checkRequired(plugin.required);
Iif (typeof checked === 'string') {
var msg = plugin.name + ' can\'t be loaded because it\'s required plugin "'
+ checked + '" do not exist or could not be loaded successfully.';
plugin.isError = true;
plugins[plugin.name] = plugin;
/* eslint-disable */
console.error(msg);
/* eslint-enable */
continue;
}
}
// 初始化
plugin.host = me;
Eif (plugin.load(param, plugins)) {
plugin.isLoaded = true;
plugin.isWorking = true;
}
else {
plugin.isError = true;
}
plugins[plugin.name] = plugin;
}
me.plugin = plugins;
/**
* 检查依赖是否加载完毕
*
* @param {Array.<string>} requires 依赖数组
* @return {boolean | string} 如果依赖全部正确加载,返回true,否则返回加载失败的插件的名称(只一个)
*/
function checkRequired(requires) {
var result = true;
for (var m = 0; m < requires.length; m++) {
var item = requires[m];
item = item.indexOf('|' > -1) ? item.split('|') : [item];
var or = false;
for (var n = 0; n < item.length; n++) {
Eif (plugins[item[n]] && !plugins[item[n]].isError) {
or = true;
break;
}
}
Iif (!or) {
result = item.join(',');
break;
}
}
return result;
}
}
/**
* 匹配皮肤
*
* @param {Object} me Controller对象实例
* @param {Object} param Controller初始化对象
*/
function setupSkin(me, param) {
var skin = (!param.hasOwnProperty('skin') || typeof param.skin !== 'string')
? 'default-' + param.uitype : param.skin + '-' + param.uitype;
var className = util.joinClassName(param.uitype, skin);
if (param.hasOwnProperty('pluginSkin') && typeof param.pluginSkin === 'string') {
className = util.joinClassName(className, param.pluginSkin);
}
me._temp.className = className;
Eif (!util.isDOM(me.container)) {
return;
}
var dataset = util.getDataset(me.container);
if (dataset.render === 'server' && dataset.rendered === 'rendered') {
return;
}
if (typeof me.container.className === 'string' && me.container.className.length > 0) {
me.container.className = util.joinClassName(me.container.className, me._temp.className);
}
else {
me.container.className = me._temp.className;
}
}
/**
* 注册事件
*
* @param {Object} me Controller对象实例
* @param {Object} param Controller初始化对象
* 这里不但注册事件,而且绑定事件上下文,Handler中this指向组件对象,即Controller子类的实例
*/
function setupEvent(me, param) {
Eif (!util.isDOM(me.container) || !param.hasOwnProperty('events')) {
return;
}
var events = {};
var inputHandler = param.events;
for (var eventName in inputHandler) {
if (typeof inputHandler[eventName] === 'function') {
inputHandler[eventName] = [inputHandler[eventName]];
}
if (!(inputHandler[eventName] instanceof Array)) {
continue;
}
var handlers = inputHandler[eventName];
events[eventName] = [];
for (var n = 0; n < handlers.length; n++) {
if (typeof handlers[n] === 'function') {
var func = util.bind(handlers[n], me);
events[eventName].push(func);
}
}
}
me._temp.events = events;
addEventHandlers(me.container, me._temp.events);
}
/**
* 绑定事件
*
* @param {HtmlElement} dom dom节点
* @param {Object} 事件hash
*/
function addEventHandlers(dom, events) {
for (var type in events) {
if (!events.hasOwnProperty(type)) {
continue;
}
var funcs = events[type];
for (var i = 0; i < funcs.length; i++) {
dom.addEventListener(type, funcs[i], false);
}
}
}
/*解绑事件
*
* @param {HtmlElement} dom dom节点
* @param {Object} 事件hash
*/
function removeEventHandlers(dom, events) {
for (var type in events) {
if (!events.hasOwnProperty(type)) {
continue;
}
var funcs = events[type];
for (var n = 0; n < funcs.length; n++) {
dom.removeEventListener(type, funcs[n]);
}
}
}
/**
* 为当前控件实例添加setter和getter
*
* @param {Controller} me 控件实例
*/
function defineProperties(me) {
/**
* datasource 数据源接口
*
* @attribute read and write
*/
Object.defineProperty(me, 'disable', {
/**
* get方法
*
* @return {string} 渲染结果
*/
get: function () {
return this._temp != null ? !!this._temp.disable : false;
},
/**
* set方法
*
* @param {boolean} v 是否禁用
*/
set: function (v) {
if (this._temp == null) {
return;
}
this._temp.disable = !!this._temp.disable;
v = v === 'false' ? false : !!v;
if (this._temp.disable === v) {
return;
}
this._temp.disable = v;
var skin = 'disable-' + this.uitype;
var funcName = v ? 'joinClassName' : 'removeClassName';
this._temp.className = util[funcName](this._temp.className, skin);
if (!util.isDOM(this.container)) {
return;
}
this.container.className = util[funcName](this.container.className, skin);
if (v) {
removeEventHandlers(this.container, this._temp.events);
}
else {
addEventHandlers(this.container, this._temp.events);
}
}
});
}
return Controller;
});
|