## drails.Element
dojo.provide('drails.Element');

dojo.require('drails.util');

drails.byId = function(element){
if(element.declaredClass == 'drails.Element')
return element;
return new drails.Element(element);
}

dojo.declare('drails.Element', null, {
constructor: function(node){
this._node = dojo.byId(node);
if(this._node == null){
console.log(node);
}
}
});

drails.Element.Methods = {
insert: function(/*String*/insertions){
for(insertion in insertions){
var position = this._positionTranslation[insertion];
var html = insertions[insertion];
var kids = this._getChildrenForInsert(html,position);
for(k in kids)
dojo.place(kids[k], this._node, position);
}
return this;
},
update: function(/*String*/html){
this._node.innerHTML = html;
return this;
},
replace: function(/*String*/html){
this.insert({after: html});
return this.remove(this._node);
},
remove: function(){
this._node.parentNode.removeChild(this._node);
return this;
},
show: function(){
this._node.style.display = '';
return this;
},
hide: function(){
this._node.style.display = 'none';
return this;
},
visible: function(){
return this._node.style.display != 'none';
},
toggle: function(){
return this[this.visible(this._node) ? "hide" : "show"]();
},
_getChildrenForInsert: function(html, position){
var div = document.createElement('div');
div.innerHTML = html;
var kids = drails.toArray(div.childNodes);
if (position == "first" || position == "after")
kids.reverse();
return kids;
},
_positionTranslation: {
bottom: "last",
top: "first",
after: "after",
before: "before",
}
};

// offer "static" methods so you can do something like:
// drails.Element.update(nodeToUpdate, htmlToUpdateWith);

drails.Element.Functions = (function(){
function functionize(method){
return function(){
var args = drails.toArray(arguments);
return method.apply(new drails.Element(args[0]),args.slice(1));
};
}
functions = {};
for(prop in drails.Element.Methods){
var value = drails.Element.Methods[prop];
if(dojo.isFunction(value) && prop[0] != "_"){
functions[prop] = functionize(value);
}
}
return functions;
})();

dojo.extend(drails.Element, drails.Element.Methods);
dojo.mixin(drails.Element, drails.Element.Functions);

## drails.util

dojo.provide('drails.util');

drails.toArray = function(arrayLikeObj){
if(dojo.isArrayLike(arrayLikeObj))
return Array.prototype.slice.call(arrayLikeObj);
return [];
}

## drails.ElementCollection

ojo.provide("drails.ElementCollection");

dojo.require("drails.Element");
dojo.require("drails.Enumerable");
dojo.require("drails.util");

drails.query = function(query){
return new drails.ElementCollection(query);
}

dojo.declare('drails.ElementCollection', null, {

constructor: function(query){
this._query = dojo.query(query);
this.length = this._query.length;
for(var i=0; i<this._query.length; i++)
this[i] = new drails.Element(this._query[i]);
},

postscript: function(){
dojo.mixin(this._query, {
_each: function(iterator){
for(var i=0; i<this.length; i++)
iterator(this[i]);
}
});
dojo.mixin(this._query, drails.Enumerable);
},

nodeList: function(){
return this._query;
},

_each: function(iterator){
for(var i=0; i<this.length; i++)
iterator(this[i]);
}

});

dojo.extend(drails.ElementCollection, drails.Enumerable);

## drails.Enumerable

/* Most of this is copied verbatim from the prototype js library
* and patched up to use dojo-isms
* http://prototypejs.org
* Prototype is also MIT licensed.
*/

dojo.provide("drails.Enumerable");

dojo.require("drails.util");

drails.Enumerable = (function(){
function passThrough(x) { return x; }
function bind(iterator, context) {
if (arguments.length < 3 && !context) return iterator;
var args = drails.toArray(arguments).slice(2);
return function() {
return iterator.apply(context, args.concat(drails.ToArray(arguments)));
}
}
var $break = { };
return {
each: function(iterator, context) {
var index = 0;
iterator = bind(iterator,context);
try {
this._each(function(value) {
iterator(value, index++);
});
} catch (e) {
if (e != $break) throw e;
}
return this;
},

eachSlice: function(number, iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var index = -number, slices = [], array = this.toArray();
while ((index += number) < array.length)
slices.push(array.slice(index, index+number));
return slices.collect(iterator, context);
},

all: function(iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var result = true;
this.each(function(value, index) {
result = result && !!iterator(value, index);
if (!result) throw $break;
});
return result;
},

any: function(iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var result = false;
this.each(function(value, index) {
if (result = !!iterator(value, index))
throw $break;
});
return result;
},

collect: function(iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var results = [];
this.each(function(value, index) {
results.push(iterator(value, index));
});
return results;
},

detect: function(iterator, context) {
iterator = bind(iterator,context);
var result;
this.each(function(value, index) {
if (iterator(value, index)) {
result = value;
throw $break;
}
});
return result;
},

findAll: function(iterator, context) {
iterator = bind(iterator,context);
var results = [];
this.each(function(value, index) {
if (iterator(value, index))
results.push(value);
});
return results;
},

grep: function(filter, iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var results = [];

if (dojo.isString(filter))
filter = new RegExp(filter);

this.each(function(value, index) {
if (filter.match(value))
results.push(iterator(value, index));
});
return results;
},

include: function(object) {
if (dojo.isFunction(this.indexOf))
if (this.indexOf(object) != -1) return true;

var found = false;
this.each(function(value) {
if (value == object) {
found = true;
throw $break;
}
});
return found;
},

inGroupsOf: function(number, fillWith) {
fillWith = arguments[1] ? fillWith : null;
return this.eachSlice(number, function(slice) {
while(slice.length < number) slice.push(fillWith);
return slice;
});
},

inject: function(memo, iterator, context) {
iterator = bind(iterator,context);
this.each(function(value, index) {
memo = iterator(memo, value, index);
});
return memo;
},

invoke: function(method) {
var args = drails.toArray(arguments).slice(1);
return this.map(function(value) {
return value[method].apply(value, args);
});
},

max: function(iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var result;
this.each(function(value, index) {
value = iterator(value, index);
if (result == null || value >= result)
result = value;
});
return result;
},

min: function(iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var result;
this.each(function(value, index) {
value = iterator(value, index);
if (result == null || value < result)
result = value;
});
return result;
},

partition: function(iterator, context) {
iterator = iterator ? bind(iterator,context) : passThrough;
var trues = [], falses = [];
this.each(function(value, index) {
(iterator(value, index) ?
trues : falses).push(value);
});
return [trues, falses];
},

pluck: function(property) {
var results = [];
this.each(function(value) {
results.push(value[property]);
});
return results;
},

reject: function(iterator, context) {
iterator = bind(iterator,context);
var results = [];
this.each(function(value, index) {
if (!iterator(value, index))
results.push(value);
});
return results;
},

sortBy: function(iterator, context) {
iterator = bind(iterator,context);
return this.map(function(value, index) {
return {value: value, criteria: iterator(value, index)};
}).sort(function(left, right) {
var a = left.criteria, b = right.criteria;
return a < b ? -1 : a > b ? 1 : 0;
}).pluck('value');
},

toArray: function() {
return this.map();
},

zip: function() {
var iterator = passThrough, args = drails.toArray(arguments);
if (Object.isFunction(args.last()))
iterator = args.pop();

var collections = [this].concat(args).map(drails.toArray);
return this.map(function(value, index) {
return iterator(collections.pluck(index));
});
},

size: function() {
return this.toArray().length;
},

inspect: function() {
return '#<Enumerable:' + this.toArray().inspect() + '>';
}
};
})();
dojo.mixin(drails.Enumerable, {
map: drails.Enumerable.collect,
find: drails.Enumerable.detect,
select: drails.Enumerable.findAll,
filter: drails.Enumerable.findAll,
member: drails.Enumerable.include,
entries: drails.Enumerable.toArray,
every: drails.Enumerable.all,
some: drails.Enumerable.any
});