Created
April 21, 2011 13:27
-
-
Save timwienk/934469 to your computer and use it in GitHub Desktop.
Add DOM object to Element.js, abstracting the selector engine part. Makes it possible to plug in other selector engines. (Note: Slick's custom combinators would have to be supported by the selector engine.)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
--- | |
name: Element | |
description: One of the most important items in MooTools. Contains the dollar function, the dollars function, and an handful of cross-browser, time-saver methods to let you easily work with HTML Elements. | |
license: MIT-style license. | |
requires: [Window, Document, Array, String, Function, Number, Slick.Parser] | |
provides: [Element, Elements, DOM, $, $$, Iframe, Selectors] | |
... | |
*/ | |
var DOM = { | |
defineSelectorEngine: function(engine){ | |
if (!engine) return this; | |
['search', 'find', 'match', 'contains', 'uidOf', 'parse'].each(function(fn){ | |
if (engine[name]) DOM[name] = engine[name]; | |
}); | |
return this; | |
}, | |
search: function(){ | |
return new Elements; | |
}, | |
find: function(){ | |
return null; | |
}, | |
match: function(){ | |
return false; | |
}, | |
contains: function(){ | |
return false; | |
}, | |
uidOf: function(node){ | |
return node.uniqueID || (node.uniqueID = String.uniqueID()); | |
}, | |
parse: Slick.parse | |
}; | |
var Element = function(tag, props){ | |
var konstructor = Element.Constructors[tag]; | |
if (konstructor) return konstructor(props); | |
if (typeof tag != 'string') return document.id(tag).set(props); | |
if (!props) props = {}; | |
if (!(/^[\w-]+$/).test(tag)){ | |
var parsed = DOM.parse(tag).expressions[0][0]; | |
tag = (parsed.tag == '*') ? 'div' : parsed.tag; | |
if (parsed.id && props.id == null) props.id = parsed.id; | |
var attributes = parsed.attributes; | |
if (attributes) for (var i = 0, l = attributes.length; i < l; i++){ | |
var attr = attributes[i]; | |
if (attr.value != null && attr.operator == '=' && props[attr.key] == null) | |
props[attr.key] = attr.value; | |
} | |
if (parsed.classList && props['class'] == null) props['class'] = parsed.classList.join(' '); | |
} | |
return document.newElement(tag, props); | |
}; | |
if (Browser.Element) Element.prototype = Browser.Element.prototype; | |
new Type('Element', Element).mirror(function(name){ | |
if (Array.prototype[name]) return; | |
var obj = {}; | |
obj[name] = function(){ | |
var results = [], args = arguments, elements = true; | |
for (var i = 0, l = this.length; i < l; i++){ | |
var element = this[i], result = results[i] = element[name].apply(element, args); | |
elements = (elements && typeOf(result) == 'element'); | |
} | |
return (elements) ? new Elements(results) : results; | |
}; | |
Elements.implement(obj); | |
}); | |
if (!Browser.Element){ | |
Element.parent = Object; | |
Element.Prototype = {'$family': Function.from('element').hide()}; | |
Element.mirror(function(name, method){ | |
Element.Prototype[name] = method; | |
}); | |
} | |
Element.Constructors = {}; | |
//<1.2compat> | |
Element.Constructors = new Hash; | |
//</1.2compat> | |
var IFrame = new Type('IFrame', function(){ | |
var params = Array.link(arguments, { | |
properties: Type.isObject, | |
iframe: function(obj){ | |
return (obj != null); | |
} | |
}); | |
var props = params.properties || {}, iframe; | |
if (params.iframe) iframe = document.id(params.iframe); | |
var onload = props.onload || function(){}; | |
delete props.onload; | |
props.id = props.name = [props.id, props.name, iframe ? (iframe.id || iframe.name) : 'IFrame_' + String.uniqueID()].pick(); | |
iframe = new Element(iframe || 'iframe', props); | |
var onLoad = function(){ | |
onload.call(iframe.contentWindow); | |
}; | |
if (window.frames[props.id]) onLoad(); | |
else iframe.addListener('load', onLoad); | |
return iframe; | |
}); | |
var Elements = this.Elements = function(nodes){ | |
if (nodes && nodes.length){ | |
var uniques = {}, node; | |
for (var i = 0; node = nodes[i++];){ | |
var uid = DOM.uidOf(node); | |
if (!uniques[uid]){ | |
uniques[uid] = true; | |
this.push(node); | |
} | |
} | |
} | |
}; | |
Elements.prototype = {length: 0}; | |
Elements.parent = Array; | |
new Type('Elements', Elements).implement({ | |
filter: function(filter, bind){ | |
if (!filter) return this; | |
return new Elements(Array.filter(this, (typeOf(filter) == 'string') ? function(item){ | |
return item.match(filter); | |
} : filter, bind)); | |
}.protect(), | |
push: function(){ | |
var length = this.length; | |
for (var i = 0, l = arguments.length; i < l; i++){ | |
var item = document.id(arguments[i]); | |
if (item) this[length++] = item; | |
} | |
return (this.length = length); | |
}.protect(), | |
unshift: function(){ | |
var items = []; | |
for (var i = 0, l = arguments.length; i < l; i++){ | |
var item = document.id(arguments[i]); | |
if (item) items.push(item); | |
} | |
return Array.prototype.unshift.apply(this, items); | |
}.protect(), | |
concat: function(){ | |
var newElements = new Elements(this); | |
for (var i = 0, l = arguments.length; i < l; i++){ | |
var item = arguments[i]; | |
if (Type.isEnumerable(item)) newElements.append(item); | |
else newElements.push(item); | |
} | |
return newElements; | |
}.protect(), | |
append: function(collection){ | |
for (var i = 0, l = collection.length; i < l; i++) this.push(collection[i]); | |
return this; | |
}.protect(), | |
empty: function(){ | |
while (this.length) delete this[--this.length]; | |
return this; | |
}.protect() | |
}); | |
//<1.2compat> | |
Elements.alias('extend', 'append'); | |
//</1.2compat> | |
(function(){ | |
// FF, IE | |
var splice = Array.prototype.splice, object = {'0': 0, '1': 1, length: 2}; | |
splice.call(object, 1, 1); | |
if (object[1] == 1) Elements.implement('splice', function(){ | |
var length = this.length; | |
splice.apply(this, arguments); | |
while (length >= this.length) delete this[length--]; | |
return this; | |
}.protect()); | |
Elements.implement(Array.prototype); | |
Array.mirror(Elements); | |
/*<ltIE8>*/ | |
var createElementAcceptsHTML; | |
try { | |
var x = document.createElement('<input name=x>'); | |
createElementAcceptsHTML = (x.name == 'x'); | |
} catch(e){} | |
var escapeQuotes = function(html){ | |
return ('' + html).replace(/&/g, '&').replace(/"/g, '"'); | |
}; | |
/*</ltIE8>*/ | |
Document.implement({ | |
newElement: function(tag, props){ | |
if (props && props.checked != null) props.defaultChecked = props.checked; | |
/*<ltIE8>*/// Fix for readonly name and type properties in IE < 8 | |
if (createElementAcceptsHTML && props){ | |
tag = '<' + tag; | |
if (props.name) tag += ' name="' + escapeQuotes(props.name) + '"'; | |
if (props.type) tag += ' type="' + escapeQuotes(props.type) + '"'; | |
tag += '>'; | |
delete props.name; | |
delete props.type; | |
} | |
/*</ltIE8>*/ | |
return this.id(this.createElement(tag)).set(props); | |
} | |
}); | |
})(); | |
Document.implement({ | |
newTextNode: function(text){ | |
return this.createTextNode(text); | |
}, | |
getDocument: function(){ | |
return this; | |
}, | |
getWindow: function(){ | |
return this.window; | |
}, | |
id: (function(){ | |
var types = { | |
string: function(id, nocash, doc){ | |
id = DOM.find(doc, '#' + id.replace(/(\W)/g, '\\$1')); | |
return (id) ? types.element(id, nocash) : null; | |
}, | |
element: function(el, nocash){ | |
$uid(el); | |
if (!nocash && !el.$family && !(/^(?:object|embed)$/i).test(el.tagName)){ | |
Object.append(el, Element.Prototype); | |
} | |
return el; | |
}, | |
object: function(obj, nocash, doc){ | |
if (obj.toElement) return types.element(obj.toElement(doc), nocash); | |
return null; | |
} | |
}; | |
types.textnode = types.whitespace = types.window = types.document = function(zero){ | |
return zero; | |
}; | |
return function(el, nocash, doc){ | |
if (el && el.$family && el.uid) return el; | |
var type = typeOf(el); | |
return (types[type]) ? types[type](el, nocash, doc || document) : null; | |
}; | |
})() | |
}); | |
if (window.$ == null) Window.implement('$', function(el, nc){ | |
return document.id(el, nc, this.document); | |
}); | |
Window.implement({ | |
getDocument: function(){ | |
return this.document; | |
}, | |
getWindow: function(){ | |
return this; | |
} | |
}); | |
[Document, Element].invoke('implement', { | |
getElements: function(expression){ | |
return DOM.search(this, expression, new Elements); | |
}, | |
getElement: function(expression){ | |
return document.id(DOM.find(this, expression)); | |
} | |
}); | |
//<1.2compat> | |
if (window.$$ == null) Window.implement('$$', function(selector){ | |
var elements = new Elements; | |
if (arguments.length == 1 && typeof selector == 'string') return DOM.search(this.document, selector, elements); | |
var args = Array.flatten(arguments); | |
for (var i = 0, l = args.length; i < l; i++){ | |
var item = args[i]; | |
switch (typeOf(item)){ | |
case 'element': elements.push(item); break; | |
case 'string': DOM.search(this.document, item, elements); | |
} | |
} | |
return elements; | |
}); | |
//</1.2compat> | |
if (window.$$ == null) Window.implement('$$', function(selector){ | |
if (arguments.length == 1){ | |
if (typeof selector == 'string') return DOM.search(this.document, selector, new Elements); | |
else if (Type.isEnumerable(selector)) return new Elements(selector); | |
} | |
return new Elements(arguments); | |
}); | |
(function(){ | |
var collected = {}, storage = {}; | |
var formProps = {input: 'checked', option: 'selected', textarea: 'value'}; | |
var get = function(uid){ | |
return (storage[uid] || (storage[uid] = {})); | |
}; | |
var clean = function(item){ | |
var uid = item.uid; | |
if (item.removeEvents) item.removeEvents(); | |
if (item.clearAttributes) item.clearAttributes(); | |
if (uid != null){ | |
delete collected[uid]; | |
delete storage[uid]; | |
} | |
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)); | |
var inserters = { | |
before: function(context, element){ | |
var parent = element.parentNode; | |
if (parent) parent.insertBefore(context, element); | |
}, | |
after: function(context, element){ | |
var parent = element.parentNode; | |
if (parent) parent.insertBefore(context, element.nextSibling); | |
}, | |
bottom: function(context, element){ | |
element.appendChild(context); | |
}, | |
top: function(context, element){ | |
element.insertBefore(context, element.firstChild); | |
} | |
}; | |
inserters.inside = inserters.bottom; | |
//<1.2compat> | |
Object.each(inserters, function(inserter, where){ | |
where = where.capitalize(); | |
var methods = {}; | |
methods['inject' + where] = function(el){ | |
inserter(this, document.id(el, true)); | |
return this; | |
}; | |
methods['grab' + where] = function(el){ | |
inserter(document.id(el, true), this); | |
return this; | |
}; | |
Element.implement(methods); | |
}); | |
//</1.2compat> | |
var injectCombinator = function(expression, combinator){ | |
if (!expression) return combinator; | |
expression = Object.clone(DOM.parse(expression)); | |
var expressions = expression.expressions; | |
for (var i = expressions.length; i--;) | |
expressions[i][0].combinator = combinator; | |
return expression; | |
}; | |
Element.implement({ | |
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; | |
}, | |
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); | |
return this; | |
}, | |
setProperties: function(attributes){ | |
for (var attribute in attributes) this.setProperty(attribute, attributes[attribute]); | |
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; | |
}, | |
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); | |
return this; | |
}, | |
removeProperties: function(){ | |
Array.each(arguments, this.removeProperty, this); | |
return this; | |
}, | |
hasClass: function(className){ | |
return this.className.clean().contains(className, ' '); | |
}, | |
addClass: function(className){ | |
if (!this.hasClass(className)) this.className = (this.className + ' ' + className).clean(); | |
return this; | |
}, | |
removeClass: function(className){ | |
this.className = this.className.replace(new RegExp('(^|\\s)' + className + '(?:\\s|$)'), '$1'); | |
return this; | |
}, | |
toggleClass: function(className, force){ | |
if (force == null) force = !this.hasClass(className); | |
return (force) ? this.addClass(className) : this.removeClass(className); | |
}, | |
adopt: function(){ | |
var parent = this, fragment, elements = Array.flatten(arguments), length = elements.length; | |
if (length > 1) parent = fragment = document.createDocumentFragment(); | |
for (var i = 0; i < length; i++){ | |
var element = document.id(elements[i], true); | |
if (element) parent.appendChild(element); | |
} | |
if (fragment) this.appendChild(fragment); | |
return this; | |
}, | |
appendText: function(text, where){ | |
return this.grab(this.getDocument().newTextNode(text), where); | |
}, | |
grab: function(el, where){ | |
inserters[where || 'bottom'](document.id(el, true), this); | |
return this; | |
}, | |
inject: function(el, where){ | |
inserters[where || 'bottom'](this, document.id(el, true)); | |
return this; | |
}, | |
replaces: function(el){ | |
el = document.id(el, true); | |
el.parentNode.replaceChild(this, el); | |
return this; | |
}, | |
wraps: function(el, where){ | |
el = document.id(el, true); | |
return this.replaces(el).grab(el, where); | |
}, | |
getPrevious: function(expression){ | |
return document.id(DOM.find(this, injectCombinator(expression, '!~'))); | |
}, | |
getAllPrevious: function(expression){ | |
return DOM.search(this, injectCombinator(expression, '!~'), new Elements); | |
}, | |
getNext: function(expression){ | |
return document.id(DOM.find(this, injectCombinator(expression, '~'))); | |
}, | |
getAllNext: function(expression){ | |
return DOM.search(this, injectCombinator(expression, '~'), new Elements); | |
}, | |
getFirst: function(expression){ | |
return document.id(DOM.search(this, injectCombinator(expression, '>'))[0]); | |
}, | |
getLast: function(expression){ | |
return document.id(DOM.search(this, injectCombinator(expression, '>')).getLast()); | |
}, | |
getParent: function(expression){ | |
return document.id(DOM.find(this, injectCombinator(expression, '!'))); | |
}, | |
getParents: function(expression){ | |
return DOM.search(this, injectCombinator(expression, '!'), new Elements); | |
}, | |
getSiblings: function(expression){ | |
return DOM.search(this, injectCombinator(expression, '~~'), new Elements); | |
}, | |
getChildren: function(expression){ | |
return DOM.search(this, injectCombinator(expression, '>'), new Elements); | |
}, | |
getWindow: function(){ | |
return this.ownerDocument.window; | |
}, | |
getDocument: function(){ | |
return this.ownerDocument; | |
}, | |
getElementById: function(id){ | |
return document.id(DOM.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1'))); | |
}, | |
getSelected: function(){ | |
this.selectedIndex; // Safari 3.2.1 | |
return new Elements(Array.from(this.options).filter(function(option){ | |
return option.selected; | |
})); | |
}, | |
toQueryString: function(){ | |
var queryString = []; | |
this.getElements('input, select, textarea').each(function(el){ | |
var type = el.type; | |
if (!el.name || el.disabled || type == 'submit' || type == 'reset' || type == 'file' || type == 'image') return; | |
var value = (el.get('tag') == 'select') ? el.getSelected().map(function(opt){ | |
// IE | |
return document.id(opt).get('value'); | |
}) : ((type == 'radio' || type == 'checkbox') && !el.checked) ? null : el.get('value'); | |
Array.from(value).each(function(val){ | |
if (typeof val != 'undefined') queryString.push(encodeURIComponent(el.name) + '=' + encodeURIComponent(val)); | |
}); | |
}); | |
return queryString.join('&'); | |
}, | |
destroy: function(){ | |
var children = clean(this).getElementsByTagName('*'); | |
Array.each(children, clean); | |
Element.dispose(this); | |
return null; | |
}, | |
empty: function(){ | |
Array.from(this.childNodes).each(Element.dispose); | |
return this; | |
}, | |
dispose: function(){ | |
return (this.parentNode) ? this.parentNode.removeChild(this) : this; | |
}, | |
match: function(expression){ | |
return !expression || DOM.match(this, expression); | |
} | |
}); | |
var cleanClone = function(node, element, keepid){ | |
if (!keepid) node.setAttributeNode(document.createAttribute('id')); | |
if (node.clearAttributes){ | |
node.clearAttributes(); | |
node.mergeAttributes(element); | |
node.removeAttribute('uid'); | |
if (node.options){ | |
var no = node.options, eo = element.options; | |
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]; | |
}; | |
Element.implement('clone', function(contents, keepid){ | |
contents = contents !== false; | |
var clone = this.cloneNode(contents), i; | |
if (contents){ | |
var ce = clone.getElementsByTagName('*'), te = this.getElementsByTagName('*'); | |
for (i = ce.length; i--;) cleanClone(ce[i], te[i], keepid); | |
} | |
cleanClone(clone, this, keepid); | |
if (Browser.ie){ | |
var co = clone.getElementsByTagName('object'), to = this.getElementsByTagName('object'); | |
for (i = co.length; i--;) co[i].outerHTML = to[i].outerHTML; | |
} | |
return document.id(clone); | |
}); | |
var contains = {contains: function(element){ | |
return DOM.contains(this, element); | |
}}; | |
if (!document.contains) Document.implement(contains); | |
if (!document.createElement('div').contains) Element.implement(contains); | |
//<1.2compat> | |
Element.implement('hasChild', function(element){ | |
return this !== element && this.contains(element); | |
}); | |
//</1.2compat> | |
[Element, Window, Document].invoke('implement', { | |
addListener: function(type, fn){ | |
if (type == 'unload'){ | |
var old = fn, self = this; | |
fn = function(){ | |
self.removeListener('unload', fn); | |
old(); | |
}; | |
} else { | |
collected[$uid(this)] = this; | |
} | |
if (this.addEventListener) this.addEventListener(type, fn, !!arguments[2]); | |
else this.attachEvent('on' + type, fn); | |
return this; | |
}, | |
removeListener: function(type, fn){ | |
if (this.removeEventListener) this.removeEventListener(type, fn, !!arguments[2]); | |
else this.detachEvent('on' + type, fn); | |
return this; | |
}, | |
retrieve: function(property, dflt){ | |
var storage = get($uid(this)), prop = storage[property]; | |
if (dflt != null && prop == null) prop = storage[property] = dflt; | |
return prop != null ? prop : null; | |
}, | |
store: function(property, value){ | |
var storage = get($uid(this)); | |
storage[property] = value; | |
return this; | |
}, | |
eliminate: function(property){ | |
var storage = get($uid(this)); | |
delete storage[property]; | |
return this; | |
} | |
}); | |
// IE purge | |
if (window.attachEvent && !window.addEventListener) window.addListener('unload', function(){ | |
Object.each(collected, clean); | |
if (window.CollectGarbage) CollectGarbage(); | |
}); | |
})(); | |
Element.Properties = {}; | |
//<1.2compat> | |
Element.Properties = new Hash; | |
//</1.2compat> | |
Element.Properties.style = { | |
set: function(style){ | |
this.style.cssText = style; | |
}, | |
get: function(){ | |
return this.style.cssText; | |
}, | |
erase: function(){ | |
this.style.cssText = ''; | |
} | |
}; | |
Element.Properties.tag = { | |
get: function(){ | |
return this.tagName.toLowerCase(); | |
} | |
}; | |
(function(maxLength){ | |
if (maxLength != null) Element.Properties.maxlength = Element.Properties.maxLength = { | |
get: function(){ | |
var maxlength = this.getAttribute('maxLength'); | |
return maxlength == maxLength ? null : maxlength; | |
} | |
}; | |
})(document.createElement('input').getAttribute('maxLength')); | |
Element.Properties.html = (function(){ | |
var tableTest = Function.attempt(function(){ | |
var table = document.createElement('table'); | |
table.innerHTML = '<tr><td></td></tr>'; | |
}); | |
var wrapper = document.createElement('div'); | |
var translations = { | |
table: [1, '<table>', '</table>'], | |
select: [1, '<select>', '</select>'], | |
tbody: [2, '<table><tbody>', '</tbody></table>'], | |
tr: [3, '<table><tbody><tr>', '</tr></tbody></table>'] | |
}; | |
translations.thead = translations.tfoot = translations.tbody; | |
var html = { | |
set: function(){ | |
var html = Array.flatten(arguments).join(''); | |
var wrap = (!tableTest && translations[this.get('tag')]); | |
if (wrap){ | |
var first = wrapper; | |
first.innerHTML = wrap[1] + html + wrap[2]; | |
for (var i = wrap[0]; i--;) first = first.firstChild; | |
this.empty().adopt(first.childNodes); | |
} else { | |
this.innerHTML = html; | |
} | |
} | |
}; | |
html.erase = html.set; | |
return html; | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Source/Element/Element.js b/Source/Element/Element.js | |
index 67ede25..14d1518 100644 | |
--- a/Source/Element/Element.js | |
+++ b/Source/Element/Element.js | |
@@ -7,13 +7,49 @@ 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, Number, Slick.Parser] | |
-provides: [Element, Elements, $, $$, Iframe, Selectors] | |
+provides: [Element, Elements, DOM, $, $$, Iframe, Selectors] | |
... | |
*/ | |
+var DOM = { | |
+ | |
+ defineSelectorEngine: function(engine){ | |
+ if (!engine) return this; | |
+ | |
+ ['search', 'find', 'match', 'contains', 'uidOf', 'parse'].each(function(fn){ | |
+ if (engine[name]) DOM[name] = engine[name]; | |
+ }); | |
+ | |
+ return this; | |
+ }, | |
+ | |
+ search: function(){ | |
+ return new Elements; | |
+ }, | |
+ | |
+ find: function(){ | |
+ return null; | |
+ }, | |
+ | |
+ match: function(){ | |
+ return false; | |
+ }, | |
+ | |
+ contains: function(){ | |
+ return false; | |
+ }, | |
+ | |
+ uidOf: function(node){ | |
+ return node.uniqueID || (node.uniqueID = String.uniqueID()); | |
+ }, | |
+ | |
+ parse: Slick.parse | |
+ | |
+}; | |
+ | |
var Element = function(tag, props){ | |
var konstructor = Element.Constructors[tag]; | |
if (konstructor) return konstructor(props); | |
@@ -22,7 +58,7 @@ var Element = function(tag, props){ | |
if (!props) props = {}; | |
if (!(/^[\w-]+$/).test(tag)){ | |
- var parsed = Slick.parse(tag).expressions[0][0]; | |
+ var parsed = DOM.parse(tag).expressions[0][0]; | |
tag = (parsed.tag == '*') ? 'div' : parsed.tag; | |
if (parsed.id && props.id == null) props.id = parsed.id; | |
@@ -103,7 +139,7 @@ var Elements = this.Elements = function(nodes){ | |
if (nodes && nodes.length){ | |
var uniques = {}, node; | |
for (var i = 0; node = nodes[i++];){ | |
- var uid = Slick.uidOf(node); | |
+ var uid = DOM.uidOf(node); | |
if (!uniques[uid]){ | |
uniques[uid] = true; | |
this.push(node); | |
@@ -239,7 +275,7 @@ Document.implement({ | |
var types = { | |
string: function(id, nocash, doc){ | |
- id = Slick.find(doc, '#' + id.replace(/(\W)/g, '\\$1')); | |
+ id = DOM.find(doc, '#' + id.replace(/(\W)/g, '\\$1')); | |
return (id) ? types.element(id, nocash) : null; | |
}, | |
@@ -291,55 +327,26 @@ Window.implement({ | |
[Document, Element].invoke('implement', { | |
getElements: function(expression){ | |
- return Slick.search(this, expression, new Elements); | |
+ return DOM.search(this, expression, new Elements); | |
}, | |
getElement: function(expression){ | |
- return document.id(Slick.find(this, expression)); | |
+ return document.id(DOM.find(this, expression)); | |
} | |
}); | |
//<1.2compat> | |
-(function(search, find, match){ | |
- | |
- this.Selectors = {}; | |
- var pseudos = this.Selectors.Pseudo = new Hash(); | |
- | |
- var addSlickPseudos = function(){ | |
- for (var name in pseudos) if (pseudos.hasOwnProperty(name)){ | |
- Slick.definePseudo(name, pseudos[name]); | |
- delete pseudos[name]; | |
- } | |
- }; | |
- | |
- Slick.search = function(context, expression, append){ | |
- addSlickPseudos(); | |
- return search.call(this, context, expression, append); | |
- }; | |
- | |
- Slick.find = function(context, expression){ | |
- addSlickPseudos(); | |
- return find.call(this, context, expression); | |
- }; | |
- | |
- Slick.match = function(node, selector){ | |
- addSlickPseudos(); | |
- return match.call(this, node, selector); | |
- }; | |
- | |
-})(Slick.search, Slick.find, Slick.match); | |
- | |
if (window.$$ == null) Window.implement('$$', function(selector){ | |
var elements = new Elements; | |
- if (arguments.length == 1 && typeof selector == 'string') return Slick.search(this.document, selector, elements); | |
+ if (arguments.length == 1 && typeof selector == 'string') return DOM.search(this.document, selector, elements); | |
var args = Array.flatten(arguments); | |
for (var i = 0, l = args.length; i < l; i++){ | |
var item = args[i]; | |
switch (typeOf(item)){ | |
case 'element': elements.push(item); break; | |
- case 'string': Slick.search(this.document, item, elements); | |
+ case 'string': DOM.search(this.document, item, elements); | |
} | |
} | |
return elements; | |
@@ -349,7 +356,7 @@ if (window.$$ == null) Window.implement('$$', function(selector){ | |
if (window.$$ == null) Window.implement('$$', function(selector){ | |
if (arguments.length == 1){ | |
- if (typeof selector == 'string') return Slick.search(this.document, selector, new Elements); | |
+ if (typeof selector == 'string') return DOM.search(this.document, selector, new Elements); | |
else if (Type.isEnumerable(selector)) return new Elements(selector); | |
} | |
return new Elements(arguments); | |
@@ -381,7 +388,7 @@ var camels = ['defaultValue', 'accessKey', 'cellPadding', 'cellSpacing', 'colSpa | |
var bools = ['compact', 'nowrap', 'ismap', 'declare', 'noshade', 'checked', 'disabled', 'readOnly', 'multiple', 'selected', | |
'noresize', 'defer', 'defaultChecked' | |
]; | |
- var attributes = { | |
+var attributes = { | |
'html': 'innerHTML', | |
'class': 'className', | |
'for': 'htmlFor', | |
@@ -451,7 +458,7 @@ Object.each(inserters, function(inserter, where){ | |
var injectCombinator = function(expression, combinator){ | |
if (!expression) return combinator; | |
- expression = Object.clone(Slick.parse(expression)); | |
+ expression = Object.clone(DOM.parse(expression)); | |
var expressions = expression.expressions; | |
for (var i = expressions.length; i--;) | |
@@ -578,43 +585,43 @@ Element.implement({ | |
}, | |
getPrevious: function(expression){ | |
- return document.id(Slick.find(this, injectCombinator(expression, '!~'))); | |
+ return document.id(DOM.find(this, injectCombinator(expression, '!~'))); | |
}, | |
getAllPrevious: function(expression){ | |
- return Slick.search(this, injectCombinator(expression, '!~'), new Elements); | |
+ return DOM.search(this, injectCombinator(expression, '!~'), new Elements); | |
}, | |
getNext: function(expression){ | |
- return document.id(Slick.find(this, injectCombinator(expression, '~'))); | |
+ return document.id(DOM.find(this, injectCombinator(expression, '~'))); | |
}, | |
getAllNext: function(expression){ | |
- return Slick.search(this, injectCombinator(expression, '~'), new Elements); | |
+ return DOM.search(this, injectCombinator(expression, '~'), new Elements); | |
}, | |
getFirst: function(expression){ | |
- return document.id(Slick.search(this, injectCombinator(expression, '>'))[0]); | |
+ return document.id(DOM.search(this, injectCombinator(expression, '>'))[0]); | |
}, | |
getLast: function(expression){ | |
- return document.id(Slick.search(this, injectCombinator(expression, '>')).getLast()); | |
+ return document.id(DOM.search(this, injectCombinator(expression, '>')).getLast()); | |
}, | |
getParent: function(expression){ | |
- return document.id(Slick.find(this, injectCombinator(expression, '!'))); | |
+ return document.id(DOM.find(this, injectCombinator(expression, '!'))); | |
}, | |
getParents: function(expression){ | |
- return Slick.search(this, injectCombinator(expression, '!'), new Elements); | |
+ return DOM.search(this, injectCombinator(expression, '!'), new Elements); | |
}, | |
getSiblings: function(expression){ | |
- return Slick.search(this, injectCombinator(expression, '~~'), new Elements); | |
+ return DOM.search(this, injectCombinator(expression, '~~'), new Elements); | |
}, | |
getChildren: function(expression){ | |
- return Slick.search(this, injectCombinator(expression, '>'), new Elements); | |
+ return DOM.search(this, injectCombinator(expression, '>'), new Elements); | |
}, | |
getWindow: function(){ | |
@@ -626,7 +633,7 @@ Element.implement({ | |
}, | |
getElementById: function(id){ | |
- return document.id(Slick.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1'))); | |
+ return document.id(DOM.find(this, '#' + ('' + id).replace(/(\W)/g, '\\$1'))); | |
}, | |
getSelected: function(){ | |
@@ -671,7 +678,7 @@ Element.implement({ | |
}, | |
match: function(expression){ | |
- return !expression || Slick.match(this, expression); | |
+ return !expression || DOM.match(this, expression); | |
} | |
}); | |
@@ -711,7 +718,7 @@ Element.implement('clone', function(contents, keepid){ | |
}); | |
var contains = {contains: function(element){ | |
- return Slick.contains(this, element); | |
+ return DOM.contains(this, element); | |
}}; | |
if (!document.contains) Document.implement(contains); | |
@@ -852,4 +859,5 @@ Element.Properties.html = (function(){ | |
html.erase = html.set; | |
return html; | |
+ | |
})(); | |
diff --git a/Source/Element/Sizzle.Adapter.js b/Source/Element/Sizzle.Adapter.js | |
new file mode 100644 | |
index 0000000..bf23662 | |
--- /dev/null | |
+++ b/Source/Element/Sizzle.Adapter.js | |
@@ -0,0 +1,28 @@ | |
+/* | |
+--- | |
+name: Sizzle.Adapter | |
+description: Hooks Sizzle into MooTools. | |
+provides: Sizzle.Adapter | |
+requires: Sizzle | |
+... | |
+*/ | |
+ | |
+DOM.defineSelectorEngine({ | |
+ | |
+ search: function(context, expression, append){ | |
+ return Sizzle(expression, context, append); | |
+ }, | |
+ | |
+ find: function(context, expression){ | |
+ return Sizzle(expression, context)[0]; | |
+ }, | |
+ | |
+ match: function(node, selector){ | |
+ return Sizzle.matches(selector, [node]).length > 0; | |
+ }, | |
+ | |
+ contains: function(context, node){ | |
+ return Sizzle.contains(context, node); | |
+ } | |
+ | |
+}); | |
diff --git a/Source/Slick/Slick.Adapter.js b/Source/Slick/Slick.Adapter.js | |
new file mode 100644 | |
index 0000000..2e506b8 | |
--- /dev/null | |
+++ b/Source/Slick/Slick.Adapter.js | |
@@ -0,0 +1,47 @@ | |
+/* | |
+--- | |
+name: Slick.Adapter | |
+description: Hooks Slick into MooTools. | |
+provides: Slick.Adapter | |
+requires: [Slick.Finder, Slick.Parser] | |
+... | |
+*/ | |
+ | |
+DOM.defineSelectorEngine(Slick); | |
+ | |
+//<1.2compat> | |
+ | |
+(function(search, find, match){ | |
+ | |
+ this.Selectors = {}; | |
+ var pseudos = this.Selectors.Pseudo = new Hash(); | |
+ | |
+ var addSlickPseudos = function(){ | |
+ for (var name in pseudos) if (pseudos.hasOwnProperty(name)){ | |
+ Slick.definePseudo(name, pseudos[name]); | |
+ delete pseudos[name]; | |
+ } | |
+ }; | |
+ | |
+ DOM.defineSelectorEngine({ | |
+ | |
+ search: function(context, expression, append){ | |
+ addSlickPseudos(); | |
+ return search.call(this, context, expression, append); | |
+ }, | |
+ | |
+ find: function(context, expression){ | |
+ addSlickPseudos(); | |
+ return find.call(this, context, expression); | |
+ }, | |
+ | |
+ match: function(node, selector){ | |
+ addSlickPseudos(); | |
+ return match.call(this, node, selector); | |
+ } | |
+ | |
+ }); | |
+ | |
+})(Slick.search, Slick.find, Slick.match); | |
+ | |
+//</1.2compat> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
--- | |
name: Sizzle.Adapter | |
description: Hooks Sizzle into MooTools. | |
provides: Sizzle.Adapter | |
requires: Sizzle | |
... | |
*/ | |
DOM.defineSelectorEngine({ | |
search: function(context, expression, append){ | |
return Sizzle(expression, context, append); | |
}, | |
find: function(context, expression){ | |
return Sizzle(expression, context)[0]; | |
}, | |
match: function(node, selector){ | |
return Sizzle.matches(selector, [node]).length > 0; | |
}, | |
contains: function(context, node){ | |
return Sizzle.contains(context, node); | |
} | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
--- | |
name: Slick.Adapter | |
description: Hooks Slick into MooTools. | |
provides: Slick.Adapter | |
requires: [Slick.Finder, Slick.Parser] | |
... | |
*/ | |
DOM.defineSelectorEngine(Slick); | |
//<1.2compat> | |
(function(search, find, match){ | |
this.Selectors = {}; | |
var pseudos = this.Selectors.Pseudo = new Hash(); | |
var addSlickPseudos = function(){ | |
for (var name in pseudos) if (pseudos.hasOwnProperty(name)){ | |
Slick.definePseudo(name, pseudos[name]); | |
delete pseudos[name]; | |
} | |
}; | |
DOM.defineSelectorEngine({ | |
search: function(context, expression, append){ | |
addSlickPseudos(); | |
return search.call(this, context, expression, append); | |
}, | |
find: function(context, expression){ | |
addSlickPseudos(); | |
return find.call(this, context, expression); | |
}, | |
match: function(node, selector){ | |
addSlickPseudos(); | |
return match.call(this, node, selector); | |
} | |
}); | |
})(Slick.search, Slick.find, Slick.match); | |
//</1.2compat> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment