原帖地址:http://space.flash8.net/space/?18713/viewspace-402754.html
原作者:我佛山人
/*
对HTML Element的包装
*/
var Element = new Native({
// 族名,为$type方法提供精准类型
name: ' Element ' ,
// 包装扩展的原型
legacy: window.Element,
// 初始化,使用Document对象的newElement创建对象
initialize: function (tag, props) {
// 先看有没有特殊的HTML Element
var konstructor = Element.Constructors.get(tag);
// 对特殊的HTML Element对象特别处理
if (konstructor) return konstructor(props);
// 如果提供标签名,根据标签名创建HTML Element对象
if ( typeof tag == ' string ' ) return document.newElement(tag, props);
// 设置属性
return $(tag).set(props);
},
// 执行后续处理,每为Element增加一个扩展,Elements也会同时实现
afterImplement: function (key, value) {
if ( ! Array[key]) Elements.implement(key, Elements.multi(key));
Element.Prototype[key] = value;
}
});
Element.Prototype = {$family: {name: ' element ' }};
Element.Constructors = new Hash;
// 同时对Element和Document对象进行扩展
Native.implement([Element, Document], {
// 根据选择符选择一个子Element
getElement: function (selector, notrash) {
return $( this .getElements(selector, true )[ 0 ] || null , notrash);
},
// 根据选择符选择子Element
getElements: function (tags, nocash) {
tags = tags.split( ' , ' );
var elements = [];
var ddup = (tags.length > 1 );
tags.each( function (tag) {
var partial = this .getElementsByTagName(tag.trim());
(ddup) ? elements.extend(partial) : elements = partial;
}, this );
return new Elements(elements, {ddup: ddup, cash: ! nocash});
}
});
// 用于获取保存在当前Element下的临时对象,参考Fx.Tween和Drag
Element.Storage = {
get: function (uid) {
return ( this [uid] || ( this [uid] = {}));
}
};
// 相当于当前Element的四个位置的DOM插入
Element.Inserters = new Hash({
// 在context指代的Element之前插入eleemnt
before: function (context, element) {
if (element.parentNode) element.parentNode.insertBefore(context, element);
},
// 在context指代的Element之后插入eleemnt
after: function (context, element) {
if ( ! element.parentNode) return ;
var next = element.nextSibling;
(next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
},
// 在context指代的Element内最后插入eleemnt
bottom: function (context, element) {
element.appendChild(context);
},
// 在context指代的Element内首位插入eleemnt
top: function (context, element) {
var first = element.firstChild;
(first) ? element.insertBefore(context, first) : element.appendChild(context);
}
});
// 别名
Element.Inserters.inside = Element.Inserters.bottom;
// 生成injectTop/grabTop之类的快捷方式
Element.Inserters.each( function (value, key) {
var Key = key.capitalize();
// injectTop,injectBefore,injectAfter,injectBottom
Element.implement( ' inject ' + Key, function (el) {
value( this , $(el, true ));
return this ;
});
// grabTop,grabBefore,grabAfter,grabBottom
Element.implement( ' grab ' + Key, function (el) {
value($(el, true ), this );
return this ;
});
});
Element.implement({
// 当前Element所属的Document
getDocument: function () {
return this .ownerDocument;
},
// 当前Element所属的Window
getWindow: function () {
return this .ownerDocument.getWindow();
},
// 根据ID查找当前Element下的对象
getElementById: function (id, nocash) {
var el = this .ownerDocument.getElementById(id);
if ( ! el) return null ;
for ( var parent = el.parentNode; parent != this ; parent = parent.parentNode) {
if ( ! parent) return null ;
}
return $.element(el, nocash);
},
// 万能的setter
set: function (prop, value) {
switch ($type(prop)) {
case ' object ' :
for ( var p in prop) this .set(p, prop[p]);
break ;
case ' string ' :
var property = Element.Properties.get(prop);
(property && property.set) ? property.set.apply( this , Array.slice(arguments, 1 )) : this .setProperty(prop, value);
}
return this ;
},
// 万能的getter
get: function (prop) {
var property = Element.Properties.get(prop);
return (property && property.get) ? property.get.apply( this , Array.slice(arguments, 1 )) : this .getProperty(prop);
},
// 万能的eraser
erase: function (prop) {
var property = Element.Properties.get(prop);
(property && property.erase) ? property.erase.apply( this , Array.slice(arguments, 1 )) : this .removeProperty(prop);
return this ;
},
// 判断当前Element是否匹配指定标签名
match: function (tag) {
return ( ! tag || Element.get( this , ' tag ' ) == tag);
},
// 根据where指定的位置,将当前Element注入到el
inject: function (el, where) {
Element.Inserters.get(where || ' bottom ' )( this , $(el, true ));
return this ;
},
// 根据where指定的位置,使当前Element作为el的父Element
wraps: function (el, where) {
el = $(el, true );
return this .replaces(el).grab(el, where);
},
// 和inject相反
grab: function (el, where) {
Element.Inserters.get(where || ' bottom ' )($(el, true ), this );
return this ;
},
// 追加文本
appendText: function (text, where) {
return this .grab( this .getDocument().newTextNode(text), where);
},
// 将多个对象追加到当前Element内
adopt: function () {
Array.flatten(arguments).each( function (element) {
element = $(element, true );
if (element) this .appendChild(element);
}, this );
return this ;
},
// 从DOM节点中删除
dispose: function () {
return ( this .parentNode) ? this .parentNode.removeChild( this ) : this ;
},
// 从当前Element克隆出新的Element,contents指定是否包含子节点,keepid指定是否忽略id属性
clone: function (contents, keepid) {
switch ($type( this )) {
case ' element ' :
var attributes = {};
for ( var j = 0 , l = this .attributes.length; j < l; j ++ ) {
var attribute = this .attributes[j], key = attribute.nodeName.toLowerCase();
var value = (key == ' style ' && this .style) ? this .style.cssText : attribute.nodeValue;
if ( ! $chk(value) || key == ' uid ' || (key == ' id ' && ! keepid)) continue ;
if (value != ' inherit ' && [ ' string ' , ' number ' ].contains($type(value))) attributes[key] = value;
}
var element = new Element( this .nodeName.toLowerCase(), attributes);
if (contents !== false ) {
for ( var i = 0 , k = this .childNodes.length; i < k; i ++ ) {
var child = Element.clone( this .childNodes[i], true , keepid);
if (child) element.grab(child);
}
}
return element;
// 如果当前是文本节点
case ' textnode ' : return document.newTextNode( this .nodeValue);
}
return null ;
},
// 替换节点
replaces: function (el) {
el = $(el, true );
el.parentNode.replaceChild( this , el);
return this ;
},
// 是否使用指定css类名
hasClass: function (className) {
return this .className.contains(className, ' ' );
},
// 添加指定css类名
addClass: function (className) {
if ( ! this .hasClass(className)) this .className = ( this .className + ' ' + className).clean();
return this ;
},
// 移除指定css类名
removeClass: function (className) {
this .className = this .className.replace( new RegExp( ' (^|\\s) ' + className + ' (?:\\s|$) ' ), ' $1 ' ).clean();
return this ;
},
// 切换指定css类名
toggleClass: function (className) {
return this .hasClass(className) ? this .removeClass(className) : this .addClass(className);
},
// 获取运行时的样式属性
getComputedStyle: function (property) {
// IE
if ( this .currentStyle) return this .currentStyle[property.camelCase()];
// 非IE
var computed = this .getWindow().getComputedStyle( this , null );
return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null ;
},
// 清空当前Element,包括内部节点的删除和内存释放
empty: function () {
$A( this .childNodes).each( function (node) {
Element.empty(node);
this .removeChild(node);
memfree(node);
}, this );
return this ;
},
// 销毁当前Element,删除所有有关的一切
destroy: function () {
memfree( this .empty().dispose());
return null ;
},
// 获取选中的子项,仅当<select multi>有效
getSelected: function () {
return $A( this .options).filter( function (option){
return option.selected;
});
},
// 将当前Element内的表单项数据转为查询串格式,以用于Ajax或get方式的提交
toQueryString: function () {
var queryString = [];
this .getElements( ' input, select, textarea ' ).each( function (el) {
if ( ! el.name || el.disabled) return ;
var value = (el.tagName.toLowerCase() == ' select ' ) ? Element.getSelected(el).map( function (opt) {
return opt.value;
}) : ((el.type == ' radio ' || el.type == ' checkbox ' ) && ! el.checked) ? null : el.value;
$splat(value).each( function (val) {
if (val) queryString.push(el.name + ' = ' + encodeURIComponent(val));
});
});
return queryString.join( ' & ' );
},
// 读取属性值,包括自定义属性
getProperty: function (attribute) {
var EA = Element.Attributes, key = EA.Props[attribute];
var value = (key) ? this [key] : this .getAttribute(attribute, 2 );
return (EA.Bools[attribute]) ? !! value : (key) ? value : value || null ;
},
// 根据属性列表读取相应值,以objecct方式返回结果
getProperties: function () {
var args = $A(arguments);
return args.map( function (attr) {
return this .getProperty(attr);
}, this ).associate(args);
},
// 属性设置
setProperty: function (attribute, value) {
var EA = Element.Attributes, key = EA.Props[attribute], hasValue = $defined(value);
if (key && EA.Bools[attribute]) value = (value || ! hasValue) ? true : false ;
else if ( ! hasValue) return this .removeProperty(attribute);
(key) ? this [key] = value : this .setAttribute(attribute, value);
return this ;
},
// 批量属性设置
setProperties: function (attributes) {
for ( var attribute in attributes) this .setProperty(attribute, attributes[attribute]);
return this ;
},
// 移除属性
removeProperty: function (attribute) {
var EA = Element.Attributes, key = EA.Props[attribute], isBool = (key && EA.Bools[attribute]);
(key) ? this [key] = (isBool) ? false : '' : this .removeAttribute(attribute);
return this ;
},
// 批量移除属性
removeProperties: function () {
Array.each(arguments, this .removeProperty, this );
return this ;
}
});
对HTML Element的包装
*/
var Element = new Native({
// 族名,为$type方法提供精准类型
name: ' Element ' ,
// 包装扩展的原型
legacy: window.Element,
// 初始化,使用Document对象的newElement创建对象
initialize: function (tag, props) {
// 先看有没有特殊的HTML Element
var konstructor = Element.Constructors.get(tag);
// 对特殊的HTML Element对象特别处理
if (konstructor) return konstructor(props);
// 如果提供标签名,根据标签名创建HTML Element对象
if ( typeof tag == ' string ' ) return document.newElement(tag, props);
// 设置属性
return $(tag).set(props);
},
// 执行后续处理,每为Element增加一个扩展,Elements也会同时实现
afterImplement: function (key, value) {
if ( ! Array[key]) Elements.implement(key, Elements.multi(key));
Element.Prototype[key] = value;
}
});
Element.Prototype = {$family: {name: ' element ' }};
Element.Constructors = new Hash;
// 同时对Element和Document对象进行扩展
Native.implement([Element, Document], {
// 根据选择符选择一个子Element
getElement: function (selector, notrash) {
return $( this .getElements(selector, true )[ 0 ] || null , notrash);
},
// 根据选择符选择子Element
getElements: function (tags, nocash) {
tags = tags.split( ' , ' );
var elements = [];
var ddup = (tags.length > 1 );
tags.each( function (tag) {
var partial = this .getElementsByTagName(tag.trim());
(ddup) ? elements.extend(partial) : elements = partial;
}, this );
return new Elements(elements, {ddup: ddup, cash: ! nocash});
}
});
// 用于获取保存在当前Element下的临时对象,参考Fx.Tween和Drag
Element.Storage = {
get: function (uid) {
return ( this [uid] || ( this [uid] = {}));
}
};
// 相当于当前Element的四个位置的DOM插入
Element.Inserters = new Hash({
// 在context指代的Element之前插入eleemnt
before: function (context, element) {
if (element.parentNode) element.parentNode.insertBefore(context, element);
},
// 在context指代的Element之后插入eleemnt
after: function (context, element) {
if ( ! element.parentNode) return ;
var next = element.nextSibling;
(next) ? element.parentNode.insertBefore(context, next) : element.parentNode.appendChild(context);
},
// 在context指代的Element内最后插入eleemnt
bottom: function (context, element) {
element.appendChild(context);
},
// 在context指代的Element内首位插入eleemnt
top: function (context, element) {
var first = element.firstChild;
(first) ? element.insertBefore(context, first) : element.appendChild(context);
}
});
// 别名
Element.Inserters.inside = Element.Inserters.bottom;
// 生成injectTop/grabTop之类的快捷方式
Element.Inserters.each( function (value, key) {
var Key = key.capitalize();
// injectTop,injectBefore,injectAfter,injectBottom
Element.implement( ' inject ' + Key, function (el) {
value( this , $(el, true ));
return this ;
});
// grabTop,grabBefore,grabAfter,grabBottom
Element.implement( ' grab ' + Key, function (el) {
value($(el, true ), this );
return this ;
});
});
Element.implement({
// 当前Element所属的Document
getDocument: function () {
return this .ownerDocument;
},
// 当前Element所属的Window
getWindow: function () {
return this .ownerDocument.getWindow();
},
// 根据ID查找当前Element下的对象
getElementById: function (id, nocash) {
var el = this .ownerDocument.getElementById(id);
if ( ! el) return null ;
for ( var parent = el.parentNode; parent != this ; parent = parent.parentNode) {
if ( ! parent) return null ;
}
return $.element(el, nocash);
},
// 万能的setter
set: function (prop, value) {
switch ($type(prop)) {
case ' object ' :
for ( var p in prop) this .set(p, prop[p]);
break ;
case ' string ' :
var property = Element.Properties.get(prop);
(property && property.set) ? property.set.apply( this , Array.slice(arguments, 1 )) : this .setProperty(prop, value);
}
return this ;
},
// 万能的getter
get: function (prop) {
var property = Element.Properties.get(prop);
return (property && property.get) ? property.get.apply( this , Array.slice(arguments, 1 )) : this .getProperty(prop);
},
// 万能的eraser
erase: function (prop) {
var property = Element.Properties.get(prop);
(property && property.erase) ? property.erase.apply( this , Array.slice(arguments, 1 )) : this .removeProperty(prop);
return this ;
},
// 判断当前Element是否匹配指定标签名
match: function (tag) {
return ( ! tag || Element.get( this , ' tag ' ) == tag);
},
// 根据where指定的位置,将当前Element注入到el
inject: function (el, where) {
Element.Inserters.get(where || ' bottom ' )( this , $(el, true ));
return this ;
},
// 根据where指定的位置,使当前Element作为el的父Element
wraps: function (el, where) {
el = $(el, true );
return this .replaces(el).grab(el, where);
},
// 和inject相反
grab: function (el, where) {
Element.Inserters.get(where || ' bottom ' )($(el, true ), this );
return this ;
},
// 追加文本
appendText: function (text, where) {
return this .grab( this .getDocument().newTextNode(text), where);
},
// 将多个对象追加到当前Element内
adopt: function () {
Array.flatten(arguments).each( function (element) {
element = $(element, true );
if (element) this .appendChild(element);
}, this );
return this ;
},
// 从DOM节点中删除
dispose: function () {
return ( this .parentNode) ? this .parentNode.removeChild( this ) : this ;
},
// 从当前Element克隆出新的Element,contents指定是否包含子节点,keepid指定是否忽略id属性
clone: function (contents, keepid) {
switch ($type( this )) {
case ' element ' :
var attributes = {};
for ( var j = 0 , l = this .attributes.length; j < l; j ++ ) {
var attribute = this .attributes[j], key = attribute.nodeName.toLowerCase();
var value = (key == ' style ' && this .style) ? this .style.cssText : attribute.nodeValue;
if ( ! $chk(value) || key == ' uid ' || (key == ' id ' && ! keepid)) continue ;
if (value != ' inherit ' && [ ' string ' , ' number ' ].contains($type(value))) attributes[key] = value;
}
var element = new Element( this .nodeName.toLowerCase(), attributes);
if (contents !== false ) {
for ( var i = 0 , k = this .childNodes.length; i < k; i ++ ) {
var child = Element.clone( this .childNodes[i], true , keepid);
if (child) element.grab(child);
}
}
return element;
// 如果当前是文本节点
case ' textnode ' : return document.newTextNode( this .nodeValue);
}
return null ;
},
// 替换节点
replaces: function (el) {
el = $(el, true );
el.parentNode.replaceChild( this , el);
return this ;
},
// 是否使用指定css类名
hasClass: function (className) {
return this .className.contains(className, ' ' );
},
// 添加指定css类名
addClass: function (className) {
if ( ! this .hasClass(className)) this .className = ( this .className + ' ' + className).clean();
return this ;
},
// 移除指定css类名
removeClass: function (className) {
this .className = this .className.replace( new RegExp( ' (^|\\s) ' + className + ' (?:\\s|$) ' ), ' $1 ' ).clean();
return this ;
},
// 切换指定css类名
toggleClass: function (className) {
return this .hasClass(className) ? this .removeClass(className) : this .addClass(className);
},
// 获取运行时的样式属性
getComputedStyle: function (property) {
// IE
if ( this .currentStyle) return this .currentStyle[property.camelCase()];
// 非IE
var computed = this .getWindow().getComputedStyle( this , null );
return (computed) ? computed.getPropertyValue([property.hyphenate()]) : null ;
},
// 清空当前Element,包括内部节点的删除和内存释放
empty: function () {
$A( this .childNodes).each( function (node) {
Element.empty(node);
this .removeChild(node);
memfree(node);
}, this );
return this ;
},
// 销毁当前Element,删除所有有关的一切
destroy: function () {
memfree( this .empty().dispose());
return null ;
},
// 获取选中的子项,仅当<select multi>有效
getSelected: function () {
return $A( this .options).filter( function (option){
return option.selected;
});
},
// 将当前Element内的表单项数据转为查询串格式,以用于Ajax或get方式的提交
toQueryString: function () {
var queryString = [];
this .getElements( ' input, select, textarea ' ).each( function (el) {
if ( ! el.name || el.disabled) return ;
var value = (el.tagName.toLowerCase() == ' select ' ) ? Element.getSelected(el).map( function (opt) {
return opt.value;
}) : ((el.type == ' radio ' || el.type == ' checkbox ' ) && ! el.checked) ? null : el.value;
$splat(value).each( function (val) {
if (val) queryString.push(el.name + ' = ' + encodeURIComponent(val));
});
});
return queryString.join( ' & ' );
},
// 读取属性值,包括自定义属性
getProperty: function (attribute) {
var EA = Element.Attributes, key = EA.Props[attribute];
var value = (key) ? this [key] : this .getAttribute(attribute, 2 );
return (EA.Bools[attribute]) ? !! value : (key) ? value : value || null ;
},
// 根据属性列表读取相应值,以objecct方式返回结果
getProperties: function () {
var args = $A(arguments);
return args.map( function (attr) {
return this .getProperty(attr);
}, this ).associate(args);
},
// 属性设置
setProperty: function (attribute, value) {
var EA = Element.Attributes, key = EA.Props[attribute], hasValue = $defined(value);
if (key && EA.Bools[attribute]) value = (value || ! hasValue) ? true : false ;
else if ( ! hasValue) return this .removeProperty(attribute);
(key) ? this [key] = value : this .setAttribute(attribute, value);
return this ;
},
// 批量属性设置
setProperties: function (attributes) {
for ( var attribute in attributes) this .setProperty(attribute, attributes[attribute]);
return this ;
},
// 移除属性
removeProperty: function (attribute) {
var EA = Element.Attributes, key = EA.Props[attribute], isBool = (key && EA.Bools[attribute]);
(key) ? this [key] = (isBool) ? false : '' : this .removeAttribute(attribute);
return this ;
},
// 批量移除属性
removeProperties: function () {
Array.each(arguments, this .removeProperty, this );
return this ;
}
});