/**
SmartJS基础模块
Feartures :
1. 基础公共方法
2. 基础公共对象
Update Note:
+ 2014.10.16 getObj和setObj支持array设置和获取
+ 2014.8.06 加入priorityList
+ 2014.5 :Created
@module Base
*/
_stDefine("base",function(st) {
/**
* SmartJS避免混淆的方法;
* SmartJS默认在使用window._smartJS;同时会判断window.st是否被占用,如果没占用的话,会同样映射到window.st;
* noConflict接受一个字符名(window下)或者对象,smartjs会同步到这个对象
* @method noConflict
* @param {string|object} extreme 扩展名或者是对象
* @return {_smartJS} smartJS对象
* @demo test/base/base.js [noConfilict]
*/
function noConflict(extreme) {
if (typeof extreme === 'string')
gbl[extreme] = st;
else if (extreme)
st = mergeObj(extreme, st);
return st;
}
var _config = {};
/**
* 基础方法
* @class common
*/
/**
SmartJS的配置公共参数方法
@method conf
@param {string} name 参数名
@param {object} conf 参数
@param {string} [mode='merge'] 参数设置模式,默认
1. merge,合并模式;
2. mix,混入模式;只应用原来没有的设置
3. replace,完全替换原来设置
@param {boolean} [deep] 是否深度拷贝拷贝,当mode为'merge'和'mix'有效
@demo test/base/base.js [conf]
*/
function conf(name, config, mode, deep) {
var oldConfig = _config[name];
if (config === undefined)
return oldConfig;
else {
if (typeof(mode) === 'boolean') {
deep = mode;
mode = null;
}
if (mode !== 'replace' && oldConfig) {
config = (mode === 'mix' ? mix : mergeObj)(deep || false, oldConfig, config);
}
_config[name] = config;
}
}
/**
将argument转换成array
@method sliceArgs
@param args {function} argument对象
@param [start = 0] {number} 开始位置
@return [array] 返回转换的数组
@demo test/base/base.js [slice arguments]
*/
function sliceArgs(args, start) {
return Array.prototype.slice.call(args, start || 0);
}
/*
复制数据方法,支持对象字面量和数组的复制
@method copy
@todo:st内部对象的复制功能
@param deep {boolean} 是否深度复制
@param obj {object | array} 注入的方法名
@param [exclude] {array|function} 排除合并的设置
@return 返回复制之后的对象
@demo test/base/base.js [copy]
@demo test/base/base.js [deep copy]
*/
function copy(deep, obj, exclude) {
var args = _buildMergeArgs(arguments);
return _copy(args[0], args[1], args[2]);
}
function _copy(deep, obj, exclude, group) {
var type = typeof obj,
copyObj, ns;
//构建排除方法
exclude = _buildExclude(exclude);
if (st.isPlainObject(obj)) {
copyObj = {};
group || (group = '');
st.each(obj, function(name, value) {
ns = group + name;
if (!exclude || exclude(ns))
copyObj[name] = _copy(deep, value, exclude, ns + '.');
})
} else if (st.isArray(obj)) {
copyObj = [];
st.each(obj, function(i, item) {
copyObj.push(copy(deep, item, exclude));
})
} else
copyObj = obj;
return copyObj;
}
function _buildExclude(exclude) {
if (exclude && !st.isFunction(exclude)) {
return function(name) {
return exclude.indexOf(name) === -1;
}
}
return exclude;
}
function _mergeObj(isMerge, deep, obj, defObj, group, fnCheck) {
var prop, valueType, propType;
st.each(defObj, function(name, value) {
var ng = group + name;
//判断是否拷贝
if ((fnCheck && fnCheck(ng, value) === false))
return;
ng += '.';
if ((prop = obj[name]) == null) {
obj[name] = _copy(deep, value, fnCheck, ng);
} else if (deep && st.isPlainObject(prop) && st.isPlainObject(value)) {
_mergeObj(isMerge, deep, prop, value, ng, fnCheck);
} else if (isMerge)
obj[name] = value;
});
return obj;
}
function _isDefined(name, value) {
return value !== undefined;
}
function _buildMergeArgs(args) {
args = sliceArgs(args);
if (typeof args[0] !== 'boolean') {
for (var i = args.length; i > 0; i--) {
args[i] = args[i - 1];
};
args[0] = false;
}
return args;
}
/**
合并默认数据方法,将obj中不空的内容从defObj中复制
@method mergeObj
@param [deep] {boolean} 是否深度合并
@param obj {function} 合并对象
@param defObj {function} 默认对象
@param [exclude] {array|function} 排除合并的设置
@param [isMix] {boolean} 排除合并的设置
@return [function] 返回合并之后的对象;如obj不为空时返回obj,否则返回新对象
*/
function mergeObj(deep, obj, defObj, exclude, isMix) {
var fnCheck, args = _buildMergeArgs(arguments);
if (args[2] == null || st.isEmptyObject(args[2]))
return args[1];
fnCheck = _buildExclude(args[3]);
if (args[4])
fnCheck = mergeFn(_isDefined, fnCheck);
if (!args[1])
return _copy(deep, args[2], args[3]);
else
return _mergeObj(!args[4], args[0], args[1], args[2], '', fnCheck);
}
/**
合并默认数据方法,将obj中不空的内容从defObj中复制
@method mix
@param [deep] {Number} 是否深度合并
@param obj {function} 合并对象
@param defObj {function} 默认对象
@param [exclude] {array|function} 排除合并的设置
@return [function] 返回合并之后的对象;如obj不为空时返回obj,否则返回新对象
@demo test/base/base.js [mix obj] {对象混入}
@demo test/base/base.js [mix Obj - deep copy] {对象深度混入}
@demo test/base/base.js [mix Obj - exclude] {混入-排除模式}
*/
function mix(deep, obj, defObj, exclude) {
var args = _buildMergeArgs(arguments);
return mergeObj(args[0], args[1], args[2], args[3], true);
}
/**
合并多个对象
@method mergeMulti
@param {boolean} deep 是否深度合并
@param {array} 合并的对象集合
@param {Boolean} [isMix] 是否为mix模式,默认是merge模式
@param {array|function} [exclude] 排除合并的设置
@return {object} 返回合并对象
@demo test/base/base.js [mergeMulti]
*/
function mergeMulti(deep, objs, isMix, exclude) {
var args = _buildMergeArgs(arguments),
obj, len;
deep = args[0];
isMix = args[2];
exclude = _buildExclude(args[3]);
if ((objs = args[1]) && (len = objs.length)) {
obj = objs[0];
for (var i = 1; i < len; i++) {
obj = mergeObj(deep, obj, objs[i], exclude, isMix);
}
}
return obj;
}
/**
在目标对象方法中注入方法,返回结果
@method injectFn
@param target {object} 注入的目标对象
@param name {string} 注入的方法名
@param fn {function} 注入方法
@param [before] {boolean} 是否前置注入,默认后置
@param [stopOnFalse] {boolean} 是否开启返回值为false停止后续执行
@demo test/base/base.js [inject function] {方法注入(默认后置)}
@demo test/base/base.js [inject function -- before] {前置方法注入}
@demo test/base/base.js [inject function -- stopOnFalse] {stopOnFalse模式}
*/
function injectFn(target, name, fn, before, stopOnFalse) {
if (!target && !name)
return;
var targetFn = target[name];
target[name] = before ? mergeFn(fn, targetFn, stopOnFalse) : mergeFn(targetFn, fn, stopOnFalse);
}
/**
合并方法,返回结果
@method mergeFn
@param fn {function} 目标方法
@param mergeFn {function} 合并方法,合并的方法始终在后执行
@param [stopOnFalse] {boolean} 是否开启返回值为false停止后续执行
@return [function] 返回合并之后的新方法
@demo test/base/base.js [merge function] {方法合并}
@demo test/base/base.js [merge function - stopOnFalse] {stopOnFalse模式}
*/
function mergeFn(fn, mergeFn, stopOnFalse) {
if (!mergeFn)
return fn;
if (!fn)
return mergeFn;
return function() {
var self = this,
result, args = arguments;
result = fn.apply(self, args);
if (stopOnFalse && result === false)
return result;
return mergeFn.apply(self, args);;
}
}
function handleObj(target, ns, root, fn) {
var result, i, name, len;
if (!target)
return null;
ns = ns.split('.');
for (i = root ? 1 : 0, len = ns.length; i < len; i++) {
if (name = ns[i]) {
result = fn(i, name, len);
if (result !== undefined)
return result;
}
}
return result;
}
function _getObjProp(name) {
var index;
name = name.replace(/\[([\d]*?)]/g, function(s, num) {
index = num;
return '';
});
return {
name: name,
index: index
};
}
/**
获取对象的属性或方法,支持命名空间方式获取
@method getObj
@param target {object} 目标对象
@param ns {string} 属性名称或者相对于target的路径,使用"."进行分割
@param [root] {boolean} 是否从根开始,默认从target子开始;从根开始则忽略ns的第一级
@return [object] 返回获取的属性或者方法
@demo test/base/base.js [getObj]
*/
function getObj(target, ns, root) {
var obj = target,
result;
result = handleObj(target, ns, root, function(i, name, len) {
var prop = _getObjProp(name);
obj = obj[prop.name];
if (obj && prop.index)
obj = obj[prop.index];
if (!obj)
return null;
})
return result === null ? result : obj;
}
/**
设置对象的属性或方法,支持命名空间方式设置
@method setObj
@param target {object} 目标对象
@param ns {string} 属性名称或者相对于target的路径,使用"."进行分割
@param value {object} 设置的值
@param [mode] {string} 值设置的方式,目标对象和值都为object类型有效,默认为替换;"mix" : 混入合并默认值;"merge" : 复制合并值;
@param [root] {boolean} 是否从根开始,默认从target子开始;从根开始则忽略ns的第一级
@return [object] 返回获取的属性或者方法
@demo test/base/base.js [setObj - base] {base}
@demo test/base/base.js [setObj - root mode] {root mode}
@demo test/base/base.js [setObj - merge mode] {merge mode}
@demo test/base/base.js [setObj - mix and root mode] {mix and root mode}
*/
function setObj(target, ns, value, mode, root) {
var obj = target,
_tmpl, _prop,
result;
if (typeof(mode) === 'boolean') {
_tmpl = mode;
root = mode;
mode = _tmpl;
}
result = handleObj(target, ns, root, function(i, name, len) {
var prop = _getObjProp(name),
setValue;
_prop = obj[prop.name];
if (prop.index) {
_prop || (_prop = []);
setValue = function(_value) {
_prop[prop.index] = _value;
return (obj[prop.name] = _prop);
}
} else {
setValue = function(_value) {
return (obj[prop.name] = _value);
}
}
if (i === len - 1) {
if (mode && st.isPlainObject(_prop))
(mode === 'merge' ? mergeObj : mix)(true, _prop, value);
else
setValue(value);
} else {
obj = st.isPlainObject(_prop) ? _prop : (setValue({}));
}
})
return result === null ? result : obj;
}
var escapeMap = {
"<": "<",
">": ">",
'"': """,
"'": "'",
"&": "&"
};
function applyToStr(obj) {
if (typeof obj === 'function')
obj = obj();
return obj + '';
}
function getEscape(s) {
return escapeMap[s];
}
var encodeHandler = {
html: function(content) {
return content.replace(/&(?![\w#]+;)|[<>"']/g, getEscape);
},
url: function(content) {
return encodeURIComponent(content);
}
};
/**
* 编码方法
* @method encode
* @param {string|function} content 编码内容或者是获取编码内容打的方法
* @param {string} type 编码类型;
* 1. html:html编码
* 2. url:url编码
* @return {string} 编码后的内容
*/
function encode(content, type) {
var encodeFn = encodeHandler[type] || encodeHandler.html;
return encodeFn(applyToStr(content));
}
var formatEncode = {
'@': 'url',
'$': 'html',
'#': false
};
var _regxFromat = /\{{([\s\S]*?)}}/g;
/**
* 文本格式化方法
* @method format
* @param {string} tmpl 模板内容
* @param {object} data 填充的数据对象
* @param {string} encodeType 编码类型,html,url
* @return {string} 格式化后的文本内容
*/
function format(tmpl, data, encodeType) {
if (tmpl && data) {
return tmpl.replace(_regxFromat, function(s, field) {
var enType = formatEncode[field.charAt(0)],
content;
if (enType != null) {
field = field.substr(1);
} else
enType = encodeType;
content = st.getObj(data, field);
return content == null ? '' : enType ? encode(content, enType) : content;
});
}
}
/**
权重列表,根据权重的由大到小进入插入。
具有两种item模式:
1. 默认,正常item,手动设置priority
2. self,读取item的priority属性
@class priorityList
@constructor
@param [mode] {string} item模式
@param [defaultPriority=0] {number} item模式
@demo test/base/base.js [priorityList]
*/
function priorityList(mode, defaultPriority) {
var _maxPriority = 0,
_minPriority = 0,
isSelf = mode === 'self',
_list = [],
_priority = defaultPriority || 0;
function getItem(item) {
return isSelf ? item : item.target;
}
/**
执行回调
@method add
@param item {Object} 添加对象
@param [priority] {number} 权重
@chainable
*/
function add(item, priority) {
var len = _list.length,
itemPriority;
if (isSelf)
priority = item.priority;
if (priority == null)
priority = _priority;
if (!isSelf) {
item = {
target: item,
priority: priority
}
}
//优先级判断
if (priority > _maxPriority) {
_maxPriority = priority;
_list.unshift(item);
len || (_minPriority = priority);
} else {
if (priority <= _minPriority) {
_list.push(item);
_minPriority = priority;
len || (_maxPriority = priority);
} else {
for (var i = 1; i < len; i++) {
itemPriority = _list[i].priority;
if ((itemPriority == null ? _priority : itemPriority) < priority) {
break;
}
}
if (i > len) {
_minPriority = priority;
}
_list.splice(i, 0, item);
}
}
return this;
}
/**
执行回调
@method remove
@param filter {function} 过滤函数,返回值:
1. {boolean}:是否匹配;
2. 'break' : 结束匹配;
3. 'done' : 完成匹配
@chainable
*/
function remove(filter) {
var type = typeof filter;
if (type === 'function') {
var i = 0,
result, item;
for (; item = _list[i]; i++) {
result = filter(getItem(item), i, _list);
//break立即退出
if (result === 'break')
break;
if (result) {
_list.splice(i, 1);
i--;
//完成退出
if (result === 'done')
break;
}
}
} else if (type === 'number')
_list.splice(i, 1);
return this;
}
/**
循环列表方法,默认根据priority大到小
@method each
@param [desc] {boolean} 是否降序,即根据priority由小到大
@param handler {function} 循环处理函数
@chainable
*/
function each(desc, handler) {
var i, step, item;
if (_list.length === 0)
return this;
if (typeof desc === 'function') {
handler = desc;
desc = false;
}
if (desc) {
i = _list.length - 1;
step = -1;
} else {
i = 0;
step = 1;
}
for (; item = _list[i]; i += step) {
if (handler(getItem(item), i, _list) === false) {
break;
}
}
return this;
}
return {
add: add,
remove: remove,
each: each,
/**
根据序号获取item
@method at
@param index {number} 序号
@return {object} 返回item
*/
at: function(index) {
var item = _list[index];
return item && getItem(item);
},
/**
清除所有项
@method clear
@chainable
*/
clear: function() {
_list = [];
_maxPriority = _minPriority = 0;
return this;
},
/**
获取列表长度
@method len
@return {number} 列表长度
*/
len: function() {
return _list.length;
}
};
}
return {
noConflict:noConflict,
conf: conf,
sliceArgs: sliceArgs,
copy: copy,
mix: mix,
mergeObj: mergeObj,
mergeMulti: mergeMulti,
injectFn: injectFn,
mergeFn: mergeFn,
getObj: getObj,
setObj: setObj,
encode: encode,
format: format,
priorityList: priorityList
}
});