Skip to content

Commit

Permalink
Backport getProperty and setProperty and tree walking from 2.0 to 1.4
Browse files Browse the repository at this point in the history
  • Loading branch information
Arian committed Aug 9, 2011
1 parent d35d5db commit b678e0e
Showing 1 changed file with 174 additions and 97 deletions.
271 changes: 174 additions & 97 deletions Source/Element/Element.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: One of the most important items in MooTools. Contains the dollar fu
license: MIT-style license.
requires: [Window, Document, Array, String, Function, Number, Slick.Parser, Slick.Finder]
requires: [Window, Document, Array, String, Function, Object, Number, Slick.Parser, Slick.Finder]
provides: [Element, Elements, $, $$, Iframe, Selectors]
Expand Down Expand Up @@ -376,30 +376,7 @@ var clean = function(item){
return item;
};

var camels = ['defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan', 'frameBorder', 'maxLength', 'readOnly',
'rowSpan', 'tabIndex', 'useMap'
];
var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readOnly', 'multiple', 'selected',
'noresize', 'defer', 'defaultChecked'
];
var attributes = {
'html': 'innerHTML',
'class': 'className',
'for': 'htmlFor',
'text': (function(){
var temp = document.createElement('div');
return (temp.textContent == null) ? 'innerText' : 'textContent';
})()
};
var readOnly = ['type'];
var expandos = ['value', 'defaultValue'];
var uriAttrs = /^(?:href|src|usemap)$/i;

bools = bools.associate(bools);
camels = camels.associate(camels.map(String.toLowerCase));
readOnly = readOnly.associate(readOnly);

Object.append(attributes, expandos.associate(expandos));
// Inserters

var inserters = {

Expand Down Expand Up @@ -449,42 +426,124 @@ Object.each(inserters, function(inserter, where){

//</1.2compat>

var injectCombinator = function(expression, combinator){
if (!expression) return combinator;
// getProperty / setProperty

var propertyGetters = {};
var propertySetters = {};

// properties

var properties = {};
Array.forEach([
'type', 'value', 'defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpan',
'frameBorder', 'maxLength', 'readOnly', 'rowSpan', 'tabIndex', 'useMap',
// Attributes
'attributes', 'childNodes', 'className', 'clientHeight', 'clientLeft', 'clientTop', 'clientWidth', 'firstChild',
'lastChild', 'nextSibling', 'nodeName', 'nodeType', 'nodeValue',
'offsetHeight', 'offsetLeft', 'offsetParent', 'offsetTop', 'offsetWidth',
'ownerDocument', 'parentNode', 'prefix', 'previousSibling', 'scrollHeight', 'scrollWidth', 'tabIndex', 'tagName',
'textContent', 'innerHTML'
], function(property){
properties[property.toLowerCase()] = property;
});

expression = Object.clone(Slick.parse(expression));
Object.append(properties, {
'html': 'innerHTML',
'text': (function(){
var temp = document.createElement('div');
return (temp.innerText == null) ? 'textContent' : 'innerText';
})()
});

var expressions = expression.expressions;
for (var i = expressions.length; i--;)
expressions[i][0].combinator = combinator;
Object.forEach(properties, function(real, key){
propertySetters[key] = function(node, value){
return node[real] = value;
};
propertyGetters[key] = function(node){
return node[real];
};
});

return expression;
// Booleans

var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readOnly', 'multiple', 'selected',
'noresize', 'defer', 'defaultChecked'
];

var booleans = {};
Array.forEach(bools, function(bool){
var lower = bool.toLowerCase();
booleans[lower] = bool;
propertySetters[lower] = function(node, value){
return node[bool] = !!value;
};
propertyGetters[lower] = function(node){
return !!node[bool];
};
});

var hasAttribute = document.documentElement.hasAttribute ? function(node, attribute) {
return node.hasAttribute(attribute);
} : function(node, attribute) {
node = node.getAttributeNode(attribute);
return !!(node && (node.specified || node.nodeValue));
};

Element.implement({
// Special cases

set: function(prop, value){
var property = Element.Properties[prop];
(property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
}.overloadSetter(),
Object.append(propertyGetters, Object.map({

get: function(prop){
var property = Element.Properties[prop];
return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
}.overloadGetter(),
'class': function(node){
return ('className' in node) ? node.className : node.getAttribute('class');
},

erase: function(prop){
var property = Element.Properties[prop];
(property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
return this;
'for': function(node){
return ('htmlFor' in node) ? node.htmlFor : node.getAttribute('for');
},

'href': function(node){
return node.getAttribute('href', 2);
},

'style': function(node){
return (node.style) ? node.style.cssText : node.getAttribute('style');
},

'maxlength': function(node){
return node.getAttribute('maxLength', 2);
}

}, function(getter){
return function(node, name){
var result = getter(node);
return (!result && !hasAttribute(node, name)) ? null : result;
};
}));

Object.append(propertySetters, {

'class': function(node, value){
return ('className' in node) ? node.className = value : node.setAttribute('class', value);
},

setProperty: function(attribute, value){
attribute = camels[attribute] || attribute;
if (value == null) return this.removeProperty(attribute);
var key = attributes[attribute];
(key) ? this[key] = value :
(bools[attribute]) ? this[attribute] = !!value : this.setAttribute(attribute, '' + value);
'for': function(node, value){
return ('htmlFor' in node) ? node.htmlFor = value : node.setAttribute('for', value);
},

'style': function(node, value){
return (node.style) ? node.style.cssText = value : node.setAttribute('style', value);
}

});

/* getProperty, setProperty */

Element.implement({

setProperty: function(name, value){
var setter = propertySetters[name.toLowerCase()];
if (setter) setter(this, value);
else this.setAttribute(name, value);
return this;
},

Expand All @@ -493,25 +552,22 @@ Element.implement({
return this;
},

getProperty: function(attribute){
attribute = camels[attribute] || attribute;
var key = attributes[attribute] || readOnly[attribute];
return (key) ? this[key] :
(bools[attribute]) ? !!this[attribute] :
(uriAttrs.test(attribute) ? this.getAttribute(attribute, 2) :
(key = this.getAttributeNode(attribute)) ? key.nodeValue : null) || null;
getProperty: function(name){
var getter = propertyGetters[name.toLowerCase()];
if (getter) return getter(this);
var result = this.getAttribute(name);
return (!result && !hasAttribute(this, name)) ? null : result;
},

getProperties: function(){
var args = Array.from(arguments);
return args.map(this.getProperty, this).associate(args);
},

removeProperty: function(attribute){
attribute = camels[attribute] || attribute;
var key = attributes[attribute];
(key) ? this[key] = '' :
(bools[attribute]) ? this[attribute] = false : this.removeAttribute(attribute);
removeProperty: function(name){
name = name.toLowerCase();
if (booleans[name]) this.setProperty(name, false)
this.removeAttribute(name);
return this;
},

Expand All @@ -520,6 +576,22 @@ Element.implement({
return this;
},

set: function(prop, value){
var property = Element.Properties[prop];
(property && property.set) ? property.set.call(this, value) : this.setProperty(prop, value);
}.overloadSetter(),

get: function(prop){
var property = Element.Properties[prop];
return (property && property.get) ? property.get.apply(this) : this.getProperty(prop);
}.overloadGetter(),

erase: function(prop){
var property = Element.Properties[prop];
(property && property.erase) ? property.erase.apply(this) : this.removeProperty(prop);
return this;
},

hasClass: function(className){
return this.className.clean().contains(className, ' ');
},
Expand Down Expand Up @@ -576,46 +648,54 @@ Element.implement({
wraps: function(el, where){
el = document.id(el, true);
return this.replaces(el).grab(el, where);
},
}

getPrevious: function(expression){
return document.id(Slick.find(this, injectCombinator(expression, '!~')));
},
});

getAllPrevious: function(expression){
return Slick.search(this, injectCombinator(expression, '!~'), new Elements);
},
// tree walking

getNext: function(expression){
return document.id(Slick.find(this, injectCombinator(expression, '~')));
},
var injectCombinator = function(expression, combinator){
if (!expression) return combinator;

getAllNext: function(expression){
return Slick.search(this, injectCombinator(expression, '~'), new Elements);
},
expression = Object.clone(Slick.parse(expression));

getFirst: function(expression){
return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
},
var expressions = expression.expressions;
for (var i = expressions.length; i--;)
expressions[i][0].combinator = combinator;

getLast: function(expression){
return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
},
return expression;
};

getParent: function(expression){
return document.id(Slick.find(this, injectCombinator(expression, '!')));
},
Object.forEach({
getNext: '~',
getPrevious: '!~',
getParent: '!'
}, function(combinator, method){
Element.implement(method, function(expression){
return document.id(Slick.find(this, injectCombinator(expression, combinator)));
});
});

getParents: function(expression){
return Slick.search(this, injectCombinator(expression, '!'), new Elements);
},
Object.forEach({
getAllNext: '~',
getAllPrevious: '!~',
getSiblings: '~~',
getChildren: '>',
getParents: '!'
}, function(combinator, method){
Element.implement(method, function(expression){
return Slick.search(this, injectCombinator(expression, combinator), new Elements);
});
});

Element.implement({

getSiblings: function(expression){
return Slick.search(this, injectCombinator(expression, '~~'), new Elements);
getFirst: function(expression){
return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]);
},

getChildren: function(expression){
return Slick.search(this, injectCombinator(expression, '>'), new Elements);
getLast: function(expression){
return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast());
},

getWindow: function(){
Expand Down Expand Up @@ -676,13 +756,11 @@ Element.implement({
},

clone: (function(){

var formProps = {input: 'checked', option: 'selected', textarea: 'value'};

var cleanClone = function(node, element, keepid){
var attr = node.getAttributeNode('id');
if (attr) node.removeAttributeNode(attr);
if (keepid) node.setAttribute('id', element.getAttribute('id'));

if (!keepid) node.removeAttribute('id');
if (node.clearAttributes){
node.clearAttributes();
node.mergeAttributes(element);
Expand All @@ -692,7 +770,6 @@ Element.implement({
for (var i = no.length; i--;) no[i].selected = eo[i].selected;
}
}

var prop = formProps[element.tagName.toLowerCase()];
if (prop && element[prop]) node[prop] = element[prop];
};
Expand Down

0 comments on commit b678e0e

Please sign in to comment.