eve.full.js
Jump to
Source Code
Source Code
var eve = (function(settings) {
/* Class Definition
--------------------------------*/
var c = function() {
/* Constants
--------------------------------*/
this.CLASSNAME = name;
this.BROWSER = null;
/* Public Properties
--------------------------------*/
this.settings = settings || {};//global settings
/* Private Properties
--------------------------------*/
var _uid = 0; //uid counter
var _data = {}; //data registry
/* Registry Methods
--------------------------------*/
this.getSpace = function() {
//get the arguments and transform it to an array
var args = this.args(arguments);
//what object are we looking into?
//if the first argument is not an object
//use data registry
//we do not want to use the type function
//in this case because we don't care what
//type of object it is
var data = typeof args[0] == 'object' ? args.shift() : _data;
if(args.length > 0)
{
var result;
//foreach argument
this.parse(args, function(key, value, length) {
//this is the last item
if((key+1) == length)
{
//assign it to result
//exit loop
result = data[value];
return false;
}
//the name does not exist
if(!data[value])
{
//assign result to null
//exit loop
result = null;
return false;
}
//walk the object
data = data[value];
});
return result;
}
//if no arguments
//return the whole object
return data;
};
this.setSpace = function() {
//get the arguments and transform it to an array
var args = this.args(arguments);
//what object are we looking into?
//if the first argument is not an object
//use data registry
//we do not want to use the type function
//in this case because we don't care what
//type of object it is
var data = typeof args[0] == 'object' ? args.shift() : _data;
if(args.length > 1)
{
var last, index;
//foreach argument
this.parse(args, this.bind(function(key, value, length) {
//this is the last item
if((key+1) == length)
{
//set it to the value
//exit loop
last[index] = value;
return false;
}
//the name does not exist
if(!data[value])
{
//lets create the name
data[value] = {};
if(value == '[]')
{// {test2: [{test3:1209}]}
last[index] = [];
last[index].push({});
value = 0;
data = last[index];
}
}
//walk the object
last = data;
index = value;
data = data[value];
}, this));
}
//allow chainability
return this;
};
this.freeSpace = function() {
//get the arguments and transform it to an array
var args = this.args(arguments);
//what object are we looking into?
//if the first argument is not an object
//use data registry
//we do not want to use the type function
//in this case because we don't care what
//type of object it is
var data = typeof args[0] == 'object' ? args.shift() : _data;
if(args.length > 0)
{
//foreach argument
this.parse(args, function(key, value, length) {
//this is the last item
if((key+1) == length)
{
//delete it
//exit loop
delete data[value];
return false;
}
//walk the object
data = data[value];
});
}
//allow chainability
return this;
};
this.isSpace = function() {
//get the arguments and transform it to an array
var args = this.args(arguments);
//what object are we looking into?
//if the first argument is not an object
//use data registry
//we do not want to use the type function
//in this case because we don't care what
//type of object it is
var data = typeof args[0] == 'object' ? args.shift() : _data;
if(args.length > 0)
{
//foreach argument
return this.parse(args, function(key, value, length) {
//the name does not exist
if(!data[value])
{
//exit loop
//false will be returned
return false;
}
//walk the object
data = data[value];
}, {bool: true});
}
//if no arguments
//then return false
return false;
};
/* Misc Utility Methods
--------------------------------*/
this.args = function(args) {
return Array.prototype.slice.call(args);
};
this.type = function( obj, has ) {
has = typeof has == 'string' ? [has] : has;
has = has instanceof Array ? has : [];
var value = (function(obj) {
var test, type = typeof obj;
//is it a function?
if( type == 'function' )
{
test = obj.toString();
//is it a regex?
if( ( /^\/.*\/$/ ).test(test))
{
return 'regexp';
}
if( ( /^\[object.*\]$/i ).test(test))
{
type = 'object';
}
}
if(type != 'object')
{
return type;
}
//typical cases
switch(obj)
{
case null:
return 'null';
case window:
return 'window';
case window.event:
return 'event';
case document:
return 'document';
}
//is it an eve class?
if(obj.CLASSNAME)
{
return obj.CLASSNAME;
}
if( window.event && (event.type == obj.type))
{
return 'event';
}
if( obj.nodeType !== null )
{
switch(obj.nodeType)
{
case 1:
return 'element';
case 3:
return 'textnode';
}
}
if( obj.constructor !== null )
{
switch( obj.constructor )
{
case Array:
type = 'array';
break;
case Date:
return 'date';
case RegExp:
return 'regexp';
case Object:
type = 'object';
break;
case ReferenceError:
return 'error';
default:
test = obj.constructor.toString().match( /\s*function (.*)\(/ );
if( test !== null )
{
return test[1];
}
}
}
if( obj.toString !== null )
{
test = obj.toString().match( /^\[object (.*)\]$/i );
if(test !== null)
{
switch(test[1].toLowerCase())
{
case 'window':
return 'window';
case 'event':
return 'event';
case 'math':
return 'math';
case 'error':
return 'error';
case 'nodelist':
case 'htmlcollection':
case 'elementarray':
return 'domcollection';
}
}
}
if(obj.callee != null)
{
return 'arguments';
}
return type;
})(obj);
if(has.length > 0)
{
return this.has(has, value);
}
return value;
};
this.uid = function() {
return _uid ++;
};
/* Constructor
--------------------------------*/
this.BROWSER = (function(version) {
//Go from most to least used
//IE all versions
var test = /MSIE\x20[0-9]*/g.exec(navigator.userAgent);
if(test)
{
test = test[0].replace('MS', '').split(' ');
return version ? test : test[0];
}
//FF all versions
test = /Firefox\/[0-9]*/g.exec(navigator.userAgent);
if(test)
{
test = test[0].split('/');
return version ? test : test[0];
}
//Chrome all versions
test = /Chrome\/[0-9]*/g.exec(navigator.userAgent);
if(test)
{
test = test[0].split('/');
return version ? test : test[0];
}
//Safari all versions
test = /[0-9]*\.[0-9]*\x20Safari/g.exec(navigator.userAgent);
if(test)
{
test = test[0].split(' ').reverse();
test[1] = /^[A-Z0-9]*/g.exec(test[1])[0];
return version ? test : test[0];
}
//Opera all versions
test = /^Opera\/[0-9]*/g.exec(navigator.userAgent);
if(test)
{
test = test[0].split('/');
return version ? test : test[0];
}
return version ? [navigator.userAgent, false] : navigator.userAgent;
})(true);
},
//link new class to outer
//and inner global scope
$ = new c();
/* Static Class Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
p.def = function() {
var name, args = $.args(arguments),
namespace = this.type(args[0], 'object') ? args.shift() : p;
while(this.type(args[0], 'string'))
{
name = args.shift();
if(typeof namespace[name] == 'undefined')
{
namespace[name] = {};
}
if(typeof args[0] == 'string')
{
namespace = namespace[name];
}
}
var parent = this.type(args[1], 'function') ? args[1].prototype : args[1] || {};
//build the class
var c = function() {};
//build the module
namespace[name] = function() {
// Constructor
//--------------------------------//
var args = $.args(arguments);
//check for loader
if(typeof c.prototype.__load == 'function')
{
return c.prototype.__load(c, args);
}
var instance = new c();
//check for constructor
if(typeof instance.__construct == 'function')
{
instance.__construct.apply(instance, args);
}
return instance;
};
//link module prototype and class prototype
c.prototype = namespace[name].prototype;
//add parent then the definition
this.ext(c.prototype, parent, {__parent: parent}, args[0] || {});
return this;
};
p.ext = function() {
var i, j, args = $.args(arguments), dest = args.shift();
dest = typeof dest == 'function' ? dest.prototype : dest;
for(i in args)
{
for(j in args[i])
{
dest[j] = args[i][j];
}
}
return dest;
};
return p;
})();
/* Static Object Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
p.clone = function(obj) {
var dest = {};
if(obj instanceof Array)
{
dest = [];
this.parse(obj, this.bind(function(key, value) {
dest.push(value);
}, this));
}
else if(typeof obj == 'object')
{
this.parse(obj, this.bind(function(key, value) {
dest[key] = value;
}, this));
}
else
{
dest = obj;
}
return dest;
};
p.destroy = function(obj) {
switch(this.type(obj))
{
case 'object':
//we do not want to use this.each in this case
//because we want to keep the original object reference
for(var key in obj)
{
switch(this.type(obj[key]))
{
case 'array':
case 'object':
this.destroy(obj[key]);
break;
}
delete obj[key];
}
break;
case 'array':
//we do not want to use this.each in this case
//because we want to keep the original object reference
for(var i = 0, length = obj.length; i < length; i++)
{
switch(this.type(obj))
{
case 'array':
case 'object':
this.destroy(obj[i]);
break;
}
delete obj[i];
}
break;
}
return null;
};
p.parse = p.each = function(obj, callback, options) {
options = options || {};
options.start = options.start || 0;
options.range = options.range || 0;
var key, i = 0, length = options.range ? options.start + options.range : this.size(obj);
if(obj instanceof Array)
{
//do the simple array, string parser
for(i = options.start; i < length; i++)
{
//if the callback returns false
if(callback(i, obj[i], length) === false)
{
//exit the loop
//return false
return false;
}
}
}
else if(typeof obj == 'object')
{
//do the object parser
for(key in obj)
{
if(i >= length)
{
break;
}
if(i < options.start)
{
i++;
continue;
}
//if the callback returns false
if(callback(key, obj[key]) === false)
{
//exit the loop
//return false
return false;
}
i++;
}
}
return true;
};
p.has = function(obj, value) {
switch(this.type(obj))
{
case 'object':
case 'array':
return !(this.parse(obj, function(k, v) {
if(v == value)
{
return false;
}
}));
case 'number':
obj = obj.toString();
case 'string':
return obj.search(value) != -1;
default:
return obj == value;
}
};
p.combine = function() {
var args = this.args(arguments),
dest = args.shift();
switch(typeof dest)
{
case 'object':
//foreach arguments
this.parse(args, this.bind(function(i, arg) {
//foreach obj
this.parse(arg, function(key, value){
if(dest instanceof Array)
{
dest.push(value);
}
else
{
dest[key] = value;
}
});
}, this));
break;
case 'string':
dest = dest.concat.apply(dest, args);
break;
}
return dest;
};
p.rparse = p.reach = function(obj, callback, options) {
switch(this.type(obj))
{
case 'string':
//reverse order a string
obj = this.split("").reverse().join("");
break;
default:
var list = [], dest = {};
//reverse store the keys
this.parse(obj, function(key, value) {
list.unshift(key);
});
//parse through the keys
this.parse(list, function(key, value) {
dest[value] = obj[value];
});
obj = dest;
break;
}
return this.parse(obj, callback, options);
};
p.replace = function(obj, look, change) {
switch(this.type(obj))
{
case 'array':
case 'object':
this.parse(obj, function(k,v){
if(v == look)
{
obj[k] = change;
}
});
break;
case 'string':
obj = obj.replace(new RegExp(look, 'g'), change);
break;
case 'number':
obj = parseInt(obj.toString().replace(new RegExp(look, 'g'), change));
break;
}
return obj;
};
p.size = function(obj) {
switch(typeof obj)
{
case 'object':
var i, length = 0;
for(i in obj)
{
length ++;
}
return length;
case 'number':
obj = obj.toString();
case 'array':
case 'string':
return obj.length;
}
return 0;
};
p.toJson = function(obj, options) {
var json = [];
switch(this.type(obj))
{
case 'object':
this.parse(obj, this.bind(function(k, v) {
var subJson = [k,v];
this.parse(subJson, this.bind(function(k, v) {
switch(this.type(v))
{
case 'string':
subJson[k] = '"'+v+'"';
break;
case 'object':
subJson[k] = this.toJson(v, options);
break;
case 'array':
subJson[k] = this.toJson(v, options);
break;
case 'function':
subJson[k] = v.toString();
if(!options.func)
{
return null;
}
break;
case 'undefined':
subJson[k] = 'undefined';
if(!options.undef)
{
return null;
}
break;
}
}, this));
json.push(subJson[0]+':'+subJson[1]);
}, this));
return '{'+json.join(',')+'}';
case 'array':
this.parse(obj, this.bind(function(k, v) {
switch(this.type(v))
{
case 'string':
v = '"'+v+'"';
break;
case 'object':
v = this.toJson(v, options);
break;
case 'array':
v = this.toJson(v, options);
break;
case 'function':
v = v.toString();
if(!options.func)
{
return null;
}
break;
case 'undefined':
v = 'undefined';
if(!options.undef)
{
return null;
}
break;
}
json.push(v);
}, this));
return '['+json.join(',')+']';
case 'string':
return '"'+obj+'"';
case 'number':
case 'bool':
return obj;
default:
return null;
}
};
p.toParam = function(obj, root) {
var query = [];
this.parse(obj, this.bind(function(key, value) {
var subroot = root ? root+'['+escape(key)+']' : escape(key);
key = root ? subroot : key;
switch(this.type(value))
{
case 'string':
case 'number':
query.push(key+'='+escape(value));
break;
case 'array':
query.push(this.toParam(value, subroot));
break;
case 'object':
query.push(this.toParam(value, subroot));
break;
}
}, this));
return query.join('&');
};
return p;
})();
/* Static Function Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
p.bind = function() {
//lets get the args for this.
var args = this.args(arguments);
//this is the function that bind attached to
var __method = args.shift(), __scope = args.shift();
if(typeof __method != 'function')
{
return null;
}
//now lets run this function
return function() {
//lets concat the arguments from the old one and the new one
for(var i = 0, length = arguments.length, args2 = []; i < length; i++)
{
args2.push(arguments[i]);
}
return __method.apply(__scope, args2.concat(args));
};
};
return p;
})();
/* Static String Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
p.camelize = function(string) {
string = string.replace(/\-(\w)/g, function(all, letter) {
return letter.toUpperCase();
});
return string.replace(string.charAt(0), string.charAt(0).toLowerCase());
};
p.dasherize = function(string) {
return string.replace(/[A-Z]/g, function(all, letter) {
if(letter === 0)
{
return all.toLowerCase();
}
return '-'+all.toLowerCase();
});
};
p.entities = function(string) {
return string.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/\"/g, '"');
};
p.escape = function(string) {
return escape(string);
};
p.search = function(string, substri) {
return string.match(new RegExp(substri,'g'));
};
p.isJson = function(string) {
return (/^[\],:{}\s]*$/).test(string.
replace(/\\["\\\/bfnrtu]/g,'@').
replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,']').
replace(/(?:^|:|,)(?:\s*\[)+/g,''));
};
p.strip = function(string) {
return string.replace(/<\/?[^>]+>/gi, '');
};
p.trim = function(string) {
return string.replace(/^\s+|\s+$/g ,'');
};
p.template = function(string, obj) {
this.parse(obj, this.bind(function(k, v) {
string = this.replace(string, '#'+k, v);
}, this));
return string;
};
p.toElement = function(string, i) {
string = this.createElement('div', {}, string).children();
return typeof i == 'number' ? string.get(i) : string;
};
p.truncate = function(string, length, truncation) {
if(string.length > length)
{
return string.slice(0, length) + truncation;
}
return string;
};
p.unentities = function(string) {
return string.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
};
p.unescape = function(string) {
return unescape(string);
};
p.unserialize = function(string, object) {
if(this.isJson(string))
{
eval('string = '+this._native);
return string;
}
object = object === false ? false : true;
var unserial = {};
this.parse(string.split('&'), this.bind(function(k, v) {
var t = v.split('=');
if(object)
{
if(t[0].indexOf('[') != -1)
{
var args = this.replace(this.replace(t[0], ']', '').split('['), '', '[]');
args.unshift(unserial);
args.push(t[1]);
this.set.apply(this, args) ;
return true;
}
}
unserial[t[0]] = t[1];
return true;
}, this));
return unserial;
};
p.validAlphaNum = function(str) {
return (/^([a-zA-Z0-9_-]+)$/).test(str);
};
p.validUrl = function(str) {
return (/^(([\w]+:)?\/\/)?(([\d\w]|%[a-fA-f\d]{2,2})+(:([\d\w]|%[a-fA-f\d]{2,2})+)?@)?([\d\w][-\d\w]{0,253}[\d\w]\.)+[\w]{2,4}(:[\d]+)?(\/([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)*(\?(&?([-+_~.\d\w]|%[a-fA-f\d]{2,2})=?)*)?(#([-+_~.\d\w]|%[a-fA-f\d]{2,2})*)?$/).test(str);
};
p.validEmail = function(str) {
return (/^((([a-z]|[0-9]|!|#|$|%|&|'|\*|\+|\-|\/|=|\?|\^|_|`|\{|\||\}|~)+(\.([a-z]|[0-9]|!|#|$|%|&|'|\*|\+|\-|\/|=|\?|\^|_|`|\{|\||\}|~)+)*)@((((([a-z]|[0-9])([a-z]|[0-9]|\-){0,61}([a-z]|[0-9])\.))*([a-z]|[0-9])([a-z]|[0-9]|\-){0,61}([a-z]|[0-9])\.)[\w]{2,4}|(((([0-9]){1,3}\.){3}([0-9]){1,3}))|(\[((([0-9]){1,3}\.){3}([0-9]){1,3})\])))$/).test(str);
};
return p;
})();
/* Static Number Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
p.square = function(num) {
return num * num;
};
p.hypotenuse = function(side1, side2, round) {
//pythagorean theorem
var r = Math.sqrt(this.square(side1) + this.square(side2));
if(round)
{
r = Math.round(r);
}
return r;
};
//cos A = (a² - b² - c²)/2bc
p.trigSSS = function(oppositeSide, side2, side3, round) {
var r = 180/Math.PI * Math.acos((this.square(side2) + this.square(side3) - this.square(oppositeSide)) / (2 * side2 * side3));
if(round)
{
r = Math.round(r);
}
return r;
};
//TODO: QA and fix
p.trigSAS = function(side1, oppositeAngle, side2, round) {
var r = Math.sqrt(this.square(side1) + this.square(side2) - 2 * side1 * side2 * Math.cos(oppositeAngle));
if(round)
{
r = Math.round(r);
}
return r;
};
//TODO: QA and fix
p.trigSSA = function(oppositeSide, sideMatch, angleMatch, round) {
var r = 180/Math.PI * Math.asin((Math.sin(angleMatch) * oppositeSide) / sideMatch);
if(round)
{
r = Math.round(r);
}
return r;
};
return p;
})();
/* Static Element Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
p.createElement = function(tag, attr, value, parent) {
return this.Element(document.createElement(tag), attr, value, parent);
};
p.documentSize = function() {
var windowSize = this.windowSize();
var scrollHeight = (document.compatMode != 'CSS1Compat') ? document.body.scrollHeight : document.documentElement.scrollHeight;
var scrollWidth = (document.compatMode != 'CSS1Compat') ? document.body.scrollWidth : document.documentElement.scrollWidth;
return {width: Math.max(scrollWidth, windowSize.width), height: Math.max(scrollHeight,windowSize.height)};
};
p.select = function(selector, context, index) {
if(typeof context == 'number')
{
index = context;
context = document.body;
}
context = context || document.body;
return this.Element(context).select(selector, index);
};
p.windowCenter = function() {
var viewport = this.windowSize();
return {left: Math.round(viewport.width / 2), top: Math.round(viewport.height / 2)};
};
p.windowOffset = function() {
if(typeof(window.pageYOffset)=='number')
{
return {left: window.pageXOffset, top: window.pageYOffset};
}
return {left: document.documentElement.scrollLeft, top: document.documentElement.scrollTop};
};
p.windowSize = function() {
// the more standards compliant browsers (mozilla/netscape/opera/IE7) use window.innerWidth and window.innerHeight
if (typeof window.innerWidth != 'undefined')
{
return {width: window.innerWidth, height: window.innerHeight};
}
// IE6 in standards compliant mode (i.e. with a valid doctype as the first line in the document)
if (typeof document.documentElement != 'undefined' &&
typeof document.documentElement.clientWidth != 'undefined' &&
document.documentElement.clientWidth !== 0)
{
return {width: document.documentElement.clientWidth, height: document.documentElement.clientHeight};
}
// older versions of IE
return {width: document.getElementsByTagName('body')[0].clientWidth, height: document.getElementsByTagName('body')[0].clientHeight};
};
return p;
})();
/* Static Event Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
p.keyPressed = function(e) {
if (e.keyCode)
{
if(e.keyCode == 13)
{
return 'enter';
}
return String.fromCharCode(e.keyCode);
}
if (e.which)
{
if(e.which == 13)
{
return 'enter';
}
return String.fromCharCode(e.which);
}
return null;
};
p.mousePosition = function(e) {
if (e.pageX || e.pageY)
{
return {left: e.pageX, top: e.pageY};
}
return e.clientX || e.clientY ? {left: e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
top: e.clientY + document.body.scrollTop + document.documentElement.scrollTop} : {left:0, top:0};
};
p.rightClicked = function(e) {
if(e.which)
{
return e.which == 3;
}
return e.button ? e.button == 2 : false;
};
p.stop = function(e) {
if(e.preventDefault)
{
e.preventDefault();
}
if(e.stopPropagation)
{
e.stopPropagation();
}
if(e.returnValue)
{
e.returnValue = false;
}
if(e.cancelBubble)
{
e.cancelBubble = true;
}
return this;
};
p.target = function(e) {
var t = e.target? e.target : e.srcElement;
return t.nodeType == 3 ? t.parentNode: t;
};
return p;
})();
/* Static Request Methods
--------------------------------*/
c.prototype = (function() {
var p = c.prototype; //ofuscation
var _includes = {};
p.include = function() {
var args = this.args(arguments),
url = args.shift();
//if the url is already included
if(_includes[url])
{
if(this.type(args[0], 'string'))
{
return this.include.apply(this, args);
}
args[0](_includes[url]);
return this;
}
else
{
var id = this.uid();
//lets include this
if(url.indexOf('.css') != -1)
{
_includes[url] = this.createElement('link', {id: 'css_link'+id, type:'text/css', rel:'stylesheet', href:url});
if(this.type(args[0], 'string'))
{
return this.include.apply(this, args);
}
args[0](_includes[url]);
}
else
{
_includes[url] = this.createElement('script', {id: 'js_script'+id, type:'text/javascript', src:url});
_includes[url].on('readystatechange', this.bind(function (e) {
if (_includes[url].el.readyState == 'complete' || _includes[url].el.readyState == 'loaded' )
{
if(this.type(args[0], 'string'))
{
return this.include.apply(this, args);
}
args[0](_includes[url]);
}
}, this));
_includes[url].on('load', this.bind(function (e) {
if(this.type(args[0], 'string'))
{
return this.include.apply(this, args);
}
args[0](_includes[url]);
}, this));
}
this.Element(document).select('head', 0).append(_includes[url]);
}
return this;
};
p.proxy = function(url, options) {
//set defaults for options
options = options || {};
options.data = options.data || '';
options.form = options.form || false;
options.method = options.method || 'get';
options.success = options.success || function(callback){};
options.failiure = options.failiure || function(callback){};
options.timeout = options.timeout || 0;
var id = this.uid();
//the constructor
//In IE, using the DOM to create an iframe
//does not properly register in windows.frames
//To make it work in IE we simply create a wrapper
//and set the innerHTML to a string version of the
//iframe, select that iframe and append it
//create a wrapper for the frame
//set the innerHTML of that wrapper to a string version of the iframe
//Opera needs the SRC to be a real HTML page.
var frame = this.toElement('<iframe id="frame_proxy'+id+'" name="frame_proxy'+id+'" src="//:" style="display:none;"></iframe>', 0);
//appending will happen later on
//we build a form to facilitate
//POST and GET methods to the server
var form = true, input, key;
//if we do not have a form element already
if(options.form === false)
{
//this flag is an indicator of whether a form
//was passed in the options
//this will be used when determining
//whether to remove a form or not
form = false;
//build a form using native JS
options.form = this.createElement('form', {method: options.method, action: url});
//now add the params as hidden fields in the form
var data = this.unserialize(options.data);
for(key in data)
{
input = this.createElement('input', {type: 'hidden', name: key, value: data[key]});
options.form.append(input);
}
}
else
{
options.form = $.Element(options.form);
}
//Either way lets set the target of the form to the iframe
options.form.attr('target', 'frame_proxy'+id);
//set a timeout
if(options.timeout)
{
var timeout = setTimeout(function() {
//remove the frame
setTimeout(function() {
frame.remove();
}, 1);
options.failiure(new Error('Server took to long to respond.'));
}, options.timeout);
}
//start listening to the iframe
//frame.onload will run when the page is loaded even if you
//trigger a new page to it when it's part of the document
//frame.onload is supported by FF2, FF3, Safari, IE6, IE7, Opera, Chrome
frame.on('load', function(e) {
//clear the timeout
clearTimeout(timeout);
//get the contents of the iframe
//and run callback
try
{
options.success(frame.attr('contentWindow').document.body.innerHTML);
}
catch(err)
{
options.failiure(new Error('Remote calls not supported.'));
}
//if there was not a form
//passed into options.form
if(!form)
{
//remove the form from body
options.form.remove();
}
//frame.parentNode.removeChild(frame);
//causes FF2+3 to not complete loading
//I do not have a work around for this
//remove the iframe from body
setTimeout(function() {
frame.remove();
}, 1);
});
if(frame.parent().el)
{
frame.remove();
}
//we need to append the form as well for IE or form.submit() wont work
//append frame and form to the body in that order
this.Element(document.body).append(frame);
if(!form)
{
this.Element(document.body).append(options.form);
}
//run form submit
options.form.el.submit();
//form.submit will trigger frame.onload()
//because we set the target of the form to the iframe
};
return p;
})();
/* Base Class
--------------------------------*/
$.def('Base', new function() {
/* Constants
--------------------------------*/
this.CLASSNAME = 'Base';
/* Public Methods
--------------------------------*/
this.on = function(type, callback, ref) {
var uid = $.uid();
//is this event set?
if(!$.isSpace(this, '__events', type))
{
$.setSpace(this, '__events', type, {});
}
//using bind there is no way to track by unique functions
//because bind will return the same overrided function
$.setSpace(this, '__events', type, uid, callback);
//lets make a function that will read the callbacks
//ironically using bind to make this happen
if(!$.isSpace(this, '__triggers', type))
{
$.setSpace(this, '__triggers', type, $.bind(function(){
var args = $.args(arguments), i, result = true;
//for each callback
//I did not want to use $.each
//because returning false would end the loop
//I wanted to parse through all the events
//then if one of them were false return false
//returning false used in events are used for triggers
var events = $.getSpace(this, '__events', type);
for(i in events)
{
if($.type(events[i]) == 'function' && events[i].apply(this, args) === false)
{
result = false;
}
}
return result;
}, this));
}
var off = $.bind(this.unbind, this, type, uid);
return { id: uid, type: type, unbind: off, off: off };
};
this.trigger = function(type) {
var args = $.args(arguments);
type = args.shift();
if($.isSpace(this, '__triggers', type))
{
if($.getSpace(this, '__triggers', type).apply(this, args) === false)
{
return false;
}
}
return this;
};
this.off = function(evt) {
var args = $.args(arguments), callbacks = {}, type = $.type(evt);
//if there are two arguments and the first is a string and the second is a function
switch(true)
{
case args.length == 2 && $.type(args[0]) == 'string':
var newCallBacks = {};
callbacks = $.getSpace(this, '__events', evt);
//for each event callback
$.parse(callbacks, function(key, callback) {
//if this callback does not equals
//what the user wanted to unlisten to
if($.type(args[1]) == 'function' && callback != args[1])
{
newCallBacks[key] = callback;
}
else if(key != args[1])
{
newCallBacks[key] = callback;
}
});
$.setSpace(this, '__events', evt, newCallBacks);
break;
case type == 'string':
$.setSpace(this, '__events', evt, callbacks);
break;
case type == 'number':
$.parse($.getSpace(this, '__events'), function(type, callbacks) {
callbacks = {};
//for each event callback
$.parse(callbacks, function(key, callback) {
if(key != evt)
{
callbacks[key] = callback;
}
});
$.setSpace(this, '__events', type, callbacks);
});
break;
}
return this;
};
});
/* Element Class
--------------------------------*/
$.def('Element', new function() {
/* Constants
-------------------------------------*/
this.CLASSNAME = 'Element';
/* Loader
--------------------------------*/
this.__load = function(instance, args) {
var el = null;
switch($.type(args[0]))
{
case 'string':
args[0] = document.getElementById(args[0]);
if(!args[0])
{
return null;
}
case 'element':
case 'window':
case 'document':
el = new instance();
el.__construct(args[0]);
break;
case this.CLASSNAME:
el = args[0];
break;
default:
return null;
}
if(args[1])
{
el.attr(args[1]);
}
if(args[2])
{
el.html(args[2]);
}
if(args[3])
{
$.Element(args[3]).append(el);
}
//return instance
return el;
};
/* Constructor
--------------------------------*/
this.__construct = function(el) {
this.el = this.register(el);
};
/* Registry Methods
--------------------------------*/
this.getSpace = function() {
var args = $.args(arguments);
args.unshift(cache[this.uid()]);
return $.getSpace.apply($, args);
};
this.setSpace = function() {
var args = $.args(arguments);
args.unshift(cache[this.uid()]);
$.setSpace.apply($, args);
return this;
};
this.freeSpace = function() {
var args = $.args(arguments);
args.unshift(cache[this.uid()]);
$.freeSpace.apply($, args);
return this;
};
this.isSpace = function() {
var args = $.args(arguments);
args.unshift(cache[this.uid()]);
return $.isSpace.apply($, args);
};
/* Set/Get Combination Methods
--------------------------------*/
this.attr = function() {
var args = $.args(arguments);
if(args.length == 2)
{
var obj = {};
obj[args[0]] = args[1];
args[0] = obj;
}
if($.type(args[0], 'object'))
{
$.parse(args[0], $.bind(function _attr_parse(key, value){
switch(key)
{
case 'class':
case 'className':
this.el.className = value;
break;
case 'html':
case 'innerHTML':
this.el.innerHTML = value;
break;
default:
this.el[key] = value;
break;
}
}, this));
return this;
}
switch(args[0])
{
case 'class':
case 'className':
return this.el.className;
case 'tag':
case 'tagName':
return this.el.tagName;
case 'html':
case 'innerHTML':
return this.el.innerHTML;
default:
return this.el[args[0]];
}
};
this.css = function() {
var args = $.args(arguments);
if(args.length == 2)
{
var obj = {};
obj[args[0]] = args[1];
args[0] = obj;
}
if($.type(args[0], 'object'))
{
$.parse(args[0], $.bind(function(key, value){
try
{
this.el.style[key] = value;
} catch(e) {}
}, this));
return this;
}
var r = null;
if (this.el.currentStyle)
{
//this needs to be Camelized
r = this.el.currentStyle[$.camelize(args[0])];
}
else if (window.getComputedStyle)
{
//this needs to be dasherized
r = document.defaultView.getComputedStyle(this.el,null).getPropertyValue($.dasherize(args[0]));
}
return !!(r) ? r : this.el.style[args[0]];
};
this.tag = function() {
var tag = this.attr('tag') || '';
return tag.toLowerCase();
};
this.html = function() {
if(arguments.length == 1)
{
return this.attr('html', arguments[0]);
}
return this.attr('html');
};
this.opacity = function(value) {
if(!$.type(value, ['number']))
{
if($.BROWSER[0] == 'IE')
{
return $.replace($.replace(this.css('filter'), 'alpha(opacity=', ''), ')', '');
}
return this.css('opacity');
}
this.css('opacity', value/10);
this.css('filter', 'alpha(opacity=' + value*10 + ')');
return this;
};
/* Class Methods
--------------------------------*/
this.addClass = function(name) {
if(!this.hasClass(name))
{
this.el.className += ' ' + name;
}
return this;
};
this.removeClass = function(name) {
if(this.hasClass(name))
{
this.el.className = this.el.className.replace(' ' + name, '');
this.el.className = this.el.className.replace(name + ' ', '');
if(this.el.className == name)
{
this.el.className = '';
}
}
return this;
};
this.hasClass = function hasClass(name) {
return $.has(this.el.className.split(' '), name);
};
/* Dimension Methods
--------------------------------*/
this.trueCoordinates = function() {
var position = this.truePosition(),
size = this.trueSize();
return [{left: position.left, top: position.top},
{top:position.top+size.height, left:position.left+size.width}];
};
this.truePosition = function() {
var size = this.trueSize(),
windowSize = $.windowSize(),
curleft = 0,
curtop = 0,
el = this.el;
do {
curleft += el.offsetLeft;
curtop += el.offsetTop;
} while (el = el.offsetParent);
return {
left: curleft, top: curtop,
right: windowSize.width-(curleft+size.width),
bottom: windowSize.height-(curtop+size.height)};
};
this.trueSize = function() {
var display = this.css('display'), originalWidth, originalHeight;
if (display != 'none' && display !== null) // Safari bug
{
originalHeight = this.css('offsetHeight');
originalWidth = this.css('offsetWidth');
if(originalWidth && originalHeight)
{
return {width: originalWidth, height: originalHeight};
}
return {width: this.attr('clientWidth'), height: this.attr('clientHeight')};
}
// All *Width *Height properties give 0 on elements with display none,
// so enable the element temporarily
var originalVisibility = this.css('visibility');
var originalPosition = this.css('position');
var originalDisplay = this.css('display');
this.css('visibility', 'visible');
this.css('position', 'absolute');
this.css('display', 'block');
originalHeight = this.attr('clientHeight');
originalWidth = this.attr('clientWidth');
this.css('visibility', originalVisibility);
this.css('position', originalPosition);
this.css('display', originalDisplay);
return {width: originalWidth, height: originalHeight};
};
/* Node Action Methods
--------------------------------*/
this.clone = function(children, events) {
children = $.type(children, 'boolean') ? children : true;
events = $.type(events, 'boolean') ? events : true;
//effectively clean up this node
var container = document.createElement('div');
container.appendChild(this.el.cloneNode(true));
var clone = $.toElement(container.innerHTML, 0);
//no parents
clone.el.parentNode.removeChild(clone.el);
//no children
clone.children().parse(function(k, el) {
el.remove();
});
//add back cloned registry items
cache[clone.uid()] = $.clone(this.getSpace());
if(children)
{
//do the same for children
this.children().parse(function _clone_children_recursive(k, el) {
el = el.clone(children);
clone.append(el);
});
}
//remove event callbacks
clone.freeSpace('__events');
if(events)
{
//properly add back the events
$.parse(this.getSpace('__events'), function(type, callbacks) {
$.parse(callbacks, function(id, callback) {
clone.on(type, callback);
});
});
}
return clone;
};
this.remove = function() {
if(this.el.parentNode)
{
this.el.parentNode.removeChild(this.el);
}
return this;
};
this.replace = function(el) {
el = $.Element(el);
if(this.el.parentNode)
{
this.el.parentNode.replaceChild(el.el, this.el);
}
return node;
};
this.prepend = function(el) {
el = $.Element(el);
if(this.el.childNodes.length > 0)
{
this.el.insertBefore(el.el, this.el.childNodes[0]);
return this;
}
return this.append(el);
};
this.append = function(el) {
el = $.Element(el);
this.el.appendChild(el.el);
return this
};
this.before = function(el) {
el = $.Element(el);
this.el.parentNode.insertBefore(el.el, this.el);
return this;
};
this.after = function(el) {
var next = this.next();
if(next)
{
el = $.Element(el);
this.el.parentNode.insertBefore(el.el, next.el);
}
else
{
$.Element(this.el.parentNode).append(el);
}
return this;
};
/* Traversal Methods
-------------------------------------*/
this.previous = function() {
var prev = this.el;
while(prev = prev.previousSibling)
{
if(prev.nodeType != 3)
{
return $.Element(prev);
}
}
return null;
};
this.next = function() {
var next = this.el;
while(next = next.nextSibling)
{
if(next.nodeType != 3)
{
return $.Element(next);
}
}
return null;
};
this.parent = function() {
if(this.el.parentNode)
{
return $.Element(this.el.parentNode);
}
return false;
};
this.select = function(selectors, index) {
selectors = selectors.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
if(selectors.length == 0)
{
return $.Collection([this]);
}
selectors = selectors.split(' ');
var selector = selectors.shift(), results = {}, select = [];
//div#id.class[type=field1].class[type=field1],div#id.class[type=field1].class[type=field1]
selector = $.replace(selector, ']', '');
selector = $.replace('!'+selector, ',', ',!');
//!div#id.class[type=field1.class[type=field1,!div#id.class[type=field1.class[type=field1
var subselects = selector.split(',');
//!div#id.class[type=field1.class[type=field1
$.parse(subselects, $.bind(function(k, v) {
var t = v.match(/!([a-zA-Z0-9])+/g);
var i = v.match(/#([a-zA-Z0-9_-])+/g);
var c = v.match(/\.([a-zA-Z0-9_-])+/g);
var a = v.match(/\[([a-zA-Z0-9_-])+=([a-zA-Z0-9])+/g);
t = t && t.length > 0 ? t[0].replace('!', '') : '*';
i = i && i.length > 0 ? i[0].replace('#', '') : null;
var r = i ? [document.getElementById(i)] : _collection(this.el.getElementsByTagName(t));
$.parse(r, function(k, el) {
var el = $.Element(el);
//test for id
var match1 = !i || el.attr('id') == i;
//test for tag
var match2 = t == '*' || el.tag() == t.toLowerCase();
//test for classes
var match3 = $.parse(c, function(k, c) {
if(typeof c == 'string')
{
c = c.replace('.', '');
return el.hasClass(c);
}
});
//test for attributes
var match4 = $.parse(a, function(k, a) {
a = a.replace('[', '').split('=');
return el.tag(a[0]) == a[1] || el.tag(a[0]) === true;
});
if(match1 && match2 && match3 && match4)
{
el.select(selectors.join(' ')).parse(function(k, el) {
results[el.el[expando]] = el;
});
}
});
}, this));
//transform into an array
$.parse(results, function(k, node) {
select.push(node);
});
return $.type(index, 'number') ? select[index] : $.Collection(select);
};
this.parents = function(selector, index) {
selector = selector || '*';
selector = selector.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
var select = [];
//div#id.class[type=field1].class[type=field1],div#id.class[type=field1].class[type=field1]
selector = $.replace(selector, ']', '');
selector = $.replace('!'+selector, ',', ',!');
//!div#id.class[type=field1.class[type=field1,!div#id.class[type=field1.class[type=field1
var subselects = selector.split(',');
//!div#id.class[type=field1.class[type=field1
$.parse(subselects, $.bind(function(k, v) {
var t = v.match(/!([a-zA-Z0-9])+/g);
var i = v.match(/#([a-zA-Z0-9_-])+/g);
var c = v.match(/\.([a-zA-Z0-9_-])+/g);
var a = v.match(/\[([a-zA-Z0-9_-])+=([a-zA-Z0-9])+/g);
t = t && t.length > 0 ? t[0].replace('!', '') : '*';
i = i && i.length > 0 ? i[0].replace('#', '') : null;
var element = $.Element(this.el.parentNode);
while(element.tag() != 'html')
{
//test for tag
var match1 = t == '*' || element.tag() == t;
//test for id
var match2 = !i || element.attr('id') == i;
//test for classes
var match3 = $.parse(c, function(k, c) {
if(typeof c == 'string')
{
c = c.replace('.', '');
return el.hasClass(c);
}
});
//test for attributes
var match4 = $.parse(a, function(k, a) {
a = a.replace('[', '').split('=');
return element.attr(a[0]) == a[1] || element.attr(a[0]) === true;
});
if(match1 && match2 && match3 && match4)
{
select.push(element);
}
element = element.parent();
}
}, this));
return $.type(index, 'number') ? select[index] : $.Collection(select);
};
this.children = function(selector, index) {
selector = selector || '*';
selector = selector.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
var select = [];
//div#id.class[type=field1].class[type=field1],div#id.class[type=field1].class[type=field1]
selector = $.replace(selector, ']', '');
selector = $.replace('!'+selector, ',', ',!');
//!div#id.class[type=field1.class[type=field1,!div#id.class[type=field1.class[type=field1
var subselects = selector.split(',');
//!div#id.class[type=field1.class[type=field1
$.parse(subselects, $.bind(function(k, v) {
var t = v.match(/!([a-zA-Z0-9])+/g);
var i = v.match(/#([a-zA-Z0-9_-])+/g);
var c = v.match(/\.([a-zA-Z0-9_-])+/g);
var a = v.match(/\[([a-zA-Z0-9_-])+=([a-zA-Z0-9])+/g);
t = t && t.length > 0 ? t[0].replace('!', '') : '*';
i = i && i.length > 0 ? i[0].replace('#', '') : null;
var r = _collection(this.el.childNodes);
$.parse(r, function(k, el) {
var element = $.Element(el);
//test for tag
var match1 = t == '*' || element.tag() == t;
//test for id
var match2 = !i || element.attr('id') == i;
//test for classes
var match3 = $.parse(c, function(k, c) {
if(typeof c == 'string')
{
c = c.replace('.', '');
return el.hasClass(c);
}
});
//test for attributes
var match4 = $.parse(a, function(k, a) {
a = a.replace('[', '').split('=');
return element.attr(a[0]) == a[1] || element.attr(a[0]) === true;
});
if(match1 && match2 && match3 && match4)
{
select.push(element);
}
});
}, this));
return $.type(index, 'number') ? select[index] : $.Collection(select);
};
/* Event Methods
-------------------------------------*/
this.on = function(type, callback) {
var uid = $.uid();
//is this event set?
if(!this.isSpace('__events', type))
{
this.setSpace('__fires', type, $.bind(this.fire, this, type));
if( this.el.attachEvent )
{
this.el.attachEvent('on'+type, this.getSpace('__fires', type));
}
else if(this.el.addEventListener)
{
this.el.addEventListener( type, this.getSpace('__fires', type), false );
}
else
{
this.el['on'+type] = this.getSpace('__fires', type);
}
var tag = this.tag();
//Special Case for onload
//it will only case for the first append
//this will enable onload capabilities for elements
if(type == 'load' && tag && tag != 'body' &&
tag.indexOf('frame') == -1 && tag != 'img' &&
tag != 'link' && tag != 'script') {
//find the parent
var parent = this.el;
while(parent.parentNode !== null && parent.parentNode.tagName && parent.parentNode.tagName != 'BODY')
{
parent = parent.parentNode;
}
if(parent.parentNode == null || !parent.parentNode.tagName)
{
var interval = setInterval(function() {
if(parent.parentNode !== null && parent.parentNode.tagName)
{
while(parent.parentNode !== null && parent.parentNode.tagName && parent.parentNode.tagName != 'BODY')
{
parent = parent.parentNode;
}
if(parent.parentNode !== null && parent.parentNode.tagName && parent.parentNode.tagName == 'BODY')
{
clearInterval(interval);
node.trigger('load', el);
}
}
}, 10);
setTimeout(function() {
clearInterval(interval);
}, 5000);
}
}
}
//using bind there is no way to track by unique functions
//because bind will return the same overrided function
this.setSpace('__events', type, uid, callback);
return { id: uid, type: type, off: $.bind(this.off, this, type, uid) };
};
this.trigger = function(type) {
var args = $.args(arguments);
if(document.dispatchEvent)
{
var e = false, events = {
MouseEvents: ['click', 'mousedown', 'mousemove',
'mouseout', 'mouseover', 'mouseup'],
HTMLEvents: ['abort', 'blur', 'change', 'error',
'focus', 'load', 'reset', 'resize',
'scroll', 'select', 'submit', 'unload'],
UIEvents: ['keydown', 'keypress', 'keyup']
};
$.parse(events, function(key, types) {
if($.has(types, type))
{
e = document.createEvent(key);
return false;
}
});
if(e)
{
e.initEvent(type, true, true);
this.el.dispatchEvent(e);
return this;
}
}
else if(document.fireEvent)
{
var fired = true;
try {
fired = this.el.fireEvent('on'+type)
} catch(e) {
fired = false;
}
if(fired)
{
return this;
}
}
args.unshift($.event || {});
args[0].target = args[0].currentTarget = this.el;
return this.fire.apply(this, args);
};
this.fire = function() {
var args = $.args(arguments), e = args.shift(), type = args.shift();
lastEvent = e;
args.unshift(e);
//for each callback
//I did not want to use $.each
//because returning false would end the loop
//I wanted to parse through all the events
//then if one of them were false return false
//returning false used in events are used for triggers
if(this.isSpace('__events', type))
{
var callbacks = this.getSpace('__events', type);
for(i in callbacks)
{
if($.type(callbacks[i]) == 'function')
{
callbacks[i].apply(callbacks[i], args);
}
}
}
return this;
};
this.off = function(evt) {
var args = $.args(arguments), callbacks = {};
//if there are two arguments and the first is a string and the second is a function
if(args.length == 2 && $.type(args[0], 'string'))
{
var newCallBacks = {};
var callbacks = this.getSpace('__events', evt);
//for each event callback
$.parse(callbacks, function(key, callback) {
//if this callback does not equals
//what the user wanted to unlisten to
if($.type(args[1]) == 'function' && value != args[1])
{
newCallBacks[key] = callback;
}
else if(key != args[1])
{
newCallBacks[key] = callback;
}
});
this.setSpace('__events', evt, newCallBacks);
}
//if a type was just given
else if($.type(evt) == 'string')
{
this.setSpace('__events', evt, callbacks);
}
//if a type was just given
else if($.type(evt) == 'number')
{
$.parse(this.getSpace('__events'), function(type, callbacks) {
callbacks = {};
//for each event callback
$.parse(callbacks, function _off_callbacks(key, callback) {
if(key != evt)
{
callbacks[key] = callback;
}
});
this.setSpace('__events', type, callbacks);
});
}
if(this.isSpace('__events', evt) && $.size(this.getSpace('__events', evt)) == 0)
{
if (this.el.removeEventListener)
{
this.el.removeEventListener(evt, this.getSpace('__fires', evt), false );
}
else if (this.el.detachEvent)
{
this.el.detachEvent("on"+evt, this.getSpace('__fires', evt));
}
this.freeSpace('__fires', evt)
this.freeSpace('__events', evt);
}
return this;
};
/* Misc Methods
-------------------------------------*/
this.childOf = function(el) {
el = $.Element(el);
var parent = this.parent();
while(parent)
{
if(parent.uid() == el.uid()) {
return true;
}
parent = parent.parent();
}
return false;
};
this.parentOf = function(el) {
return $.Element(el).childOf(this.el);
}
this.tween = function(styles, duration) {
var args = $.args(arguments);
if(!$.type(args[0], 'object'))
{
return this;
}
styles = args.shift();
duration = typeof args[0] == 'number' ? args.shift() : 30;
callback = typeof args[0] == 'function' ? args.shift() : false;
$.parse(styles, $.bind(function(key, value) {
this.css(key, value[0]);
}, this));
var step = 1, interval = setInterval($.bind(function(uid, styles, duration, callback, args) {
if($.BROWSER[0] != 'Firefox')
{
var args2 = $.args(arguments);
styles = args2[0];
duration = args2[1];
callback = args2[2];
args = args2[3];
}
$.parse(styles, $.bind(function(key, value) {
//find the distance between start and end
var m, increment = (parseFloat(value[1]) - parseFloat(value[0])) / duration;
switch(true)
{
case value[0].indexOf('px') != -1:
m = 'px';
break;
case value[0].indexOf('em') != -1:
m = 'em';
break;
default:
m = '';
break;
}
//case for opacity expected 1-10
if(key == 'opacity')
{
this.opacity(parseFloat(value[0]) + (increment * step));
}
else
{
this.css(key, (parseFloat(value[0]) + (increment * step))+m );
}
}, this));
if(step >= duration)
{
clearInterval(interval);
if(typeof callback == 'function')
{
callback(this, styles, duration);
}
if(args && args.length > 0)
{
this.tween.apply(this, args);
}
}
step ++;
}, this, styles, duration, callback, args), 1);
return this;
};
this.serialize = function(string) {
string = string === false ? false : true;
var serial = {};
this.select('input').parse(function(key, el) {
el = $.Element(el);
if(el.attr('type') == 'radio')
{
if(el.attr('checked'))
{
serial[el.attr('name')] = el.attr('value');
}
}
else if(el.attr('type') == 'checkbox')
{
if(el.attr('checked'))
{
serial[el.attr('name')] = el.attr('value') || 1;
}
else
{
serial[el.attr('name')] = 0;
}
}
else
{
serial[el.attr('name')] = el.attr('value');
}
});
this.select('textarea').parse(function(key, el) {
el = $.Element(el);
serial[el.attr('name')] = el.html();
});
this.select('select').parse(function(key, el) {
el = $.Element(el);
el.select('option').parse(function(k, v) {
v = $.Element(v);
if(v.attr('selected'))
{
serial[el.attr('name')] = v.attr('value');
}
});
});
if(string)
{
var newSerial = [];
$.parse(serial, function(key, value){
newSerial.push(key+'='+value);
});
return newSerial.join('&');
}
return serial;
};
this.register = function(el) {
//make an id and cache
//for this element
var id = el[expando];
if(!$.type(id, 'number'))
{
cache.push({});
el[expando] = cache.length - 1;
}
return el;
};
this.purge = function() {
delete this.el[expando];
return this;
};
this.uid = function() {
return this.el[expando];
};
/* Private Properties
-------------------------------------*/
var cache = [],
expando = $.CLASSNAME + +new Date(),
lastEvent = $.event;
/* Private Methods
-------------------------------------*/
_collection = function(list) {
var dest = [];
for(var i = 0, length = list.length; i < length; i++)
{
if(list[i].nodeType == 1)
{
dest.push(list[i]);
}
}
return dest;
};
});
//set a global event object now that
//the element class is definied
//we need this for custom events
//http://fbloggs.wordpress.com/2006/12/27/how-to-create-a-global-event-object-for-both-ie-and-firefox/
var setGlobalEvent = $.Element(document).on('click', function(e) {
e = e || window.event;
$.event = {};
for(var k in e)
{
$.event[k] = e[k];
}
setGlobalEvent.off();
});
$.Element(document).trigger('click');
/* Collection Class
--------------------------------*/
$.def('Collection', new function() {
/* Constants
-------------------------------------*/
this.CLASSNAME = 'Collection';
/* Loader
--------------------------------*/
this.__load = function(instance, args) {
var collection = [];
switch($.type(args[0]))
{
case 'string':
args[0] = document.getElementById(args[0]);
case 'element':
case 'window':
case 'document':
collection = [$.Element(args[0])];
case 'domcollection':
case 'array':
collection = new instance();
collection.__construct(args[0]);
break;
case this.CLASSNAME:
collection = args[0];
break;
default:
return null;
}
if(args[1])
{
collection.attr(args[1]);
}
if(args[2])
{
collection.html(args[2]);
}
//return instance
return collection;
};
/* Constructor
--------------------------------*/
this.__construct = function(collection) {
this.collection = [];
for(var i = 0, length = collection.length; i < length; i++)
{
this.collection.push($.Element(collection[i]));
}
this.unique();
};
/* Parser Methods
--------------------------------*/
this.parse = this.each = function(callback, options) {
$.parse(this.collection, callback, options);
return this;
};
this.get = function(num) {
if(typeof num == 'number')
{
return this.collection[num];
}
return this.collection;
};
this.map = function(method, args) {
args = $.args(args);
this.parse(function(k, el) {
el[method].apply(el, args);
});
return this;
};
this.combine = function() {
var args = $.args(arguments);
//foreach arguments
$.parse(args, $.bind(function(i, arg) {
arg = $.Collection(arg);
arg.parse(function(key, el) {
this.collection.push(el);
});
}, this));
this.unique();
return this;
};
this.pop = function(returnElement) {
returnElement = returnElement === false ? false : true;
if(returnElement)
{
return this.collection.pop();
}
this.collection.pop();
return this;
};
this.push = function(el) {
el = $.Element(el);
if(el)
{
this.collection.push(el);
}
return this;
};
this.rparse = this.reach = function(obj, callback, options) {
$.rparse(this.collection, callback, options);
return this;
};
this.shift = function(returnElement) {
returnElement = returnElement === false ? false : true;
if(returnElement)
{
return this.collection.shift();
}
this.collection.shift();
return this;
};
this.size = function() {
return this.collection.length;
};
this.unique = function() {
var unique = {};
this.parse(function(k, el) {
if($.type(el, ['Element', 'element']))
{
el = $.Element(el);
unique[el.uid()] = el;
}
});
this.collection = [];
$.parse(unique, $.bind(function(k, el) {
this.collection.push(el);
}, this));
return this;
};
this.unshift = function(el) {
el = $.Element(el);
if(el)
{
this.collection.unshift(el);
}
return this;
};
/* Other Methods
--------------------------------*/
this.html = function() {
if(arguments.length == 1)
{
return this.map('html', arguments);
}
//return them something
if(this.collection.length > 0)
{
return this.collection[0].html.apply(this.collection[0], args);
}
return null;
};
this.remove = function() {
this.map('remove', arguments);
//this is the end of the road
return null;
};
/* Pure Setter Methods
--------------------------------*/
$.parse(['set', 'unset', 'isset', 'addClass',
'removeClass', 'on', 'trigger', 'fire', 'off'],
$.bind(function(key, method) {
this[method] = function() {
return this.map(method, arguments);
};
}, this));
$.parse(['attr', 'css'], $.bind(function(key, method) {
this[method] = function() {
if(arguments.length == 1 && typeof arguments[0] == 'string')
{
//return them something
if(this.collection.length > 0)
{
return this.collection[0][method].apply(this.collection[0], args);
}
return null;
}
return this.map(method, arguments);
};
}, this));
/* Return Element Methods
--------------------------------*/
$.parse(['clone', 'previous', 'next', 'parent'],
$.bind(function(key, method) {
this[method] = function() {
var args = $.args(arguments);
this.parse($.bind(function(k, el) {
this.collection[key] = el[method].apply(el, args);
}, this));
return this;
};
}, this));
/* Return Collection Methods
--------------------------------*/
$.parse(['select', 'parents', 'children'],
$.bind(function(key, method) {
this[method] = function(selector, index) {
//produce a new collection
var collection = $.Collection([]);
this.parse(function(k, el) {
collection.combine(el[method].call(el, selector, index));
});
return collection;
};
}, this));
});
/* Component - AJAX Class
--------------------------------*/
$.def('Ajax', new function() {
$.settings.timeout = 10000;
var transport = $.BROWSER[0] == 'IE' ? new ActiveXObject("Microsoft.XMLHTTP") : new XMLHttpRequest()
/* Constants
-------------------------------------*/
this.CLASSNAME = 'Ajax';
this.STATE = {READY: 'ready', REQUEST: 'request'};
/* Constructor
--------------------------------*/
this.__construct = function(url, params) {
this.url = url;
this.params = params || null;
this.STATE = this.STATE.READY;
this.timeout = [];
this.callbacks = [];
};
/* Methods
--------------------------------*/
this.queue = function(callback) {
this.callbacks.push(callback);
return this;
};
this.abort = function() {
transport.abort();
//clear timeout
while(timeout = this.timeout.pop())
{
clearTimeout(timeout);
}
this.state = this.STATE.READY;
return this;
};
this.send = function(options) {
//set default options
options = $.combine({
method: 'POST', poll: false,
timeout: $.settings.timeout
}, options || {});
//see if this is already being requested
if(this.state != this.STATE.READY)
{
return;
}
//set the state
this.state = this.STATE.REQUEST;
//set a timeout
this.timeout.push(setTimeout($.bind(function(timeout) {
//abort it
this.abort();
}, this, true), options.timeout));
//try sending this out
try {
if(options.method.toUpperCase() == 'POST')
{
//open connection
transport.open(options.method, this.url, true);
//Send the proper header information along with the request
transport.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
transport.setRequestHeader("Content-length", $.type(this.params, 'string') ? this.params.length : 0);
transport.setRequestHeader("Connection", "close");
//give a chance for user to override
$.parse(options.headers, $.bind(function(key, value) {
if(value instanceof Array)
{
transport.setRequestHeader(value[0], value[1]);
}
}, this));
//set the response callback
transport.onreadystatechange = $.bind(this.receive, this, options);
//send it out
transport.send(this.params);
}
else
{
//open connection
transport.open(options.method, this.url+'?'+this.params, true);
//set the response callback
transport.onreadystatechange = $.bind(this.receive, this, options);
//send it out
transport.send(null);
}
} catch(e){}
return this;
};
this.receive = function(options) {
try
{
if (transport.readyState == 4 || transport.readyState == 'complete')
{
var timeout,
status = transport.status,
response = transport.responseText;
//clear timeout
while(timeout = this.timeout.pop())
{
clearTimeout(timeout);
}
//change state
this.state = this.STATE.RESPONSE;
//handle errors
if(!response)
{
response = new Error('No Response');
}
else if(status != 200)
{
response = new Error('Response Error');
}
else
{
this.lastResponse = response;
}
//run the response handler
$.parse(this.callbacks, $.bind(function(key, value){
value(response, this);
}, this));
//change state
this.state = this.STATE.READY;
//test for polling
if(options.poll)
{
//call polling
this.send(options);
}
}
} catch(e) {}
};
}, $.Base);
/* Interaction - Draggable Class
--------------------------------*/
$.def('Draggable', new function() {
this.CLASSNAME = 'Draggable';
/* Constructor
-------------------------------------*/
this.__construct = function (target, options) {
//track all binds
this.events = {};
//flag for dragging
this.dragging = false;
//set the target
this.target = this.proxy = $.Element(target);
//check if target has a draggable obj
if(this.target.isSpace('draggable'))
{
//lets destroy it
this.target.getSpace('draggable').__destruct();
}
//track original target style when the mousemove event is on
this.originalTargetStyle = {
display: this.target.css('display') || '',
visibility: this.target.css('visibility') || '',
position: this.target.css('position') || '',
left: this.target.css('left') || '',
top: this.target.css('top') || '',
marginLeft: this.target.css('left') || '',
marginTop: this.target.css('top') || ''};
//set the options
this.options = options || {};
switch($.type(this.options.handle))
{
case 'element':
this.handle = $.Element(this.options.handle);
break;
case 'Element':
this.handle = this.options.handle;
break;
case 'array':
this.options.handle[1] = !!(this.options.handle[1]) ? this.options.handle[1] : document.body;
this.handle = $.select(this.options.handle[0], this.options.handle[1]);
break;
default:
this.handle = this.target;
break;
}
this.options.snapDetection = this.options.snapDetection || 15;
//fix the snap option
if(this.options.snap)
{
//if string then it's a selector
//otherwise it can only be an element or Element
switch($.type(this.options.snap))
{
case 'array':
$.parse(this.options.snap, function(k, v) {
this.options.snap[k] = $.Element(v);
});
break;
case 'string':
this.options.snap = $.select(this.options.snap).get();
$.parse(this.options.snap, function(k, v) {
this.options.snap[k] = $.Element(v);
});
break;
case 'element':
this.options.snap = [$.Element(this.options.snap)];
break;
case 'Element':
this.options.snap = [this.options.snap];
break;
default:
this.options.snap = false;
break;
}
}
//start listening to the handler
$.setSpace(this.events, 'handle', 'mousedown', this.handle.on('mousedown', $.bind(this.start, this)));
//mark on the element that there is a drag obj associated
this.target.setSpace('draggable', this);
};
/* Methods
-------------------------------------*/
this.start = function(e) {
this.dragging = true;
//get the mouse position and target position
var mousePosition = $.mousePosition(e),
coordinates = this.target.trueCoordinates();
this.init = {
mouse: mousePosition,
position: {
left: mousePosition.left - parseInt(coordinates[0].left),
top: mousePosition.top - parseInt(coordinates[0].top)},
relative: {
left: mousePosition.left - (parseInt(this.target.css('left')) || 0),
top: mousePosition.top - (parseInt(this.target.css('top'))||0)},
margin: {
left: mousePosition.left - (parseInt(this.target.css('marginLeft')) || 0),
top: mousePosition.top - (parseInt(this.target.css('marginTop')) || 0)}};
//listen to the window and body mouse up
$.setSpace(this.events, 'window', 'mouseup', $.Element(window).on('mouseup', $.bind(this.stop, this)));
$.setSpace(this.events, 'body', 'mouseup', $.Element(document.body).on('mouseup', $.bind(this.stop, this)));
if($.BROWSER[0] == 'IE')
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
$.setSpace(this.events, 'document', 'mousemove', $.Element(document).on('mousemove', $.bind(this.drag, this)));
}
else
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
$.setSpace(this.events, 'window', 'mousemove', $.Element(window).on('mousemove', $.bind(this.drag, this)));
}
//trigger
if(this.trigger('start', this, e) === false)
{
return false;
}
//stop default action
$.stop(e);
if(this.options.proxy === true)
{
//lets make a clone of the target node called a proxy
this.proxy = this.getProxy(this.target);
}
else if(typeof this.options.proxy == 'function')
{
this.proxy = this.options.proxy(this.target);
}
else
{
this.proxy = this.target;
}
if(this.options.type == 'margin')
{
this.proxy.css('marginLeft', this.target.css('marginLeft') || 0);
this.proxy.css('marginTop', this.target.css('marginTop') || 0);
}
else
{
this.proxy.css('position', this.target.css('position')|| 'relative');
this.proxy.css('left', this.target.css('left') || 0);
this.proxy.css('top', this.target.css('top') || 0);
}
//lets switch the proxy with the real element so the user wont know the difference
this.target.css('display', 'none');
this.proxy.css('display', 'block');
this.proxy.css('visibility', this.originalTargetStyle.visibility);
};
this.drag = function(e) {
//stop default action
$.stop(e);
//some math
var mousePosition = $.mousePosition(e),
size = this.proxy.trueSize(),
relative = {
left: mousePosition.left - this.init.relative.left,
top: mousePosition.top - this.init.relative.top},
position = {
left: mousePosition.left - this.init.position.left,
top: mousePosition.top - this.init.position.top},
margin = {
left: mousePosition.left - this.init.margin.left,
top: mousePosition.top - this.init.margin.top},
coords = [
{left: position.left,
top: position.top},
{left: position.left + size.width,
top: position.top + size.height}];
//if the mouse leaves the view port lets stop dragging
if(mousePosition.left < 2 || mousePosition.top < 2)
{
this.stop(e);
return;
}
if(this.options.snap)
{
_snapCalc.call(this, coords, this.options.type == 'margin' ? margin : relative);
}
//if there is a grid lets do some epic math
if(typeof this.options.grid == 'number')
{
_gridCalc.call(this, this.options.type == 'margin' ? margin : relative);
}
//if there are container and the target passes it then lets not drag
if(this.options.container)
{
var containerCoords = _getCoords.call(this, this.options.container);
if(coords[0].left < containerCoords[0].left)
{
relative.left += containerCoords[0].left - coords[0].left;
margin.left += containerCoords[0].left - coords[0].left;
}
else if(coords[1].left > containerCoords[1].left)
{
relative.left -= coords[1].left - containerCoords[1].left;
margin.left += containerCoords[0].left - coords[0].left;
}
if(coords[0].top < containerCoords[0].top)
{
relative.top += containerCoords[0].top - coords[0].top;
margin.left += containerCoords[0].left - coords[0].left;
}
if(coords[1].top > containerCoords[1].top)
{
relative.top -= coords[1].top - containerCoords[1].top;
margin.left += containerCoords[0].left - coords[0].left;
}
}
//trigger
if(this.trigger('drag', this, e, this.options.type == 'margin' ? margin : relative, position) === false)
{
return false;
}
//if there's a direction option and it's not set to vertical
if(!this.options.direction || this.options.direction != 'vertical')
{
if(this.options.type == 'margin')
{
this.proxy.css('marginLeft', margin.left+'px');
}
else
{
this.proxy.css('left', relative.left+'px');
}
}
//if there's a direction option and it's not set to horizontal
if(!this.options.direction || this.options.direction != 'horizontal')
{
if(this.options.type == 'margin')
{
this.proxy.css('marginTop', margin.top+'px');
}
else
{
this.proxy.css('top', relative.top+'px');
}
}
};
this.stop = function(e) {
if(!this.dragging)
{
return;
}
this.dragging = false;
//unlisten
this.events.window.mouseup.off();
this.events.body.mouseup.off();
if($.BROWSER[0] == 'IE')
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
this.events.document.mousemove.off();
}
else
{
this.events.window.mousemove.off();
}
if(this.trigger('stop', this, e) === false)
{
return false;
}
$.stop(e);
//lets bring the real node back and destroy the proxy
if(this.options.type == 'margin')
{
this.target.css('marginLeft', this.proxy.css('marginLeft'));
this.target.css('marginTop', this.proxy.css('marginTop'));
}
else
{
this.target.css('position', 'relative');
this.target.css('top', this.proxy.css('top'));
this.target.css('left', this.proxy.css('left'));
}
if(this.options.proxy === true || typeof this.options.proxy == 'function')
{
//lets make a clone of the target node called a proxy
this.removeProxy(this.proxy);
}
this.target.css('visibility', this.originalTargetStyle.visibility);
this.target.css('display', this.originalTargetStyle.display);
};
this.getProxy = function(target) {
var proxy = target.clone();
target.after(proxy);
return proxy;
};
this.removeProxy = function(proxy) {
proxy.remove();
return this;
};
/* Private Methods
-------------------------------------*/
var _getCoords = function (coords) {
if($.type(coords, 'array') &&
typeof coords[0].left == 'number' &&
typeof coords[0].top == 'number' &&
typeof coords[1].left == 'number' &&
typeof coords[1].top == 'number')
{
return coords;
}
else if($.type(coords, ['element', 'Element']))
{
return $.Element(coords).trueCoordinates();
}
coords = $.documentSize();
return [{left: 0, top: 0}, {left:coords.width, top: coords.height}];
};
var _gridCalc = function(position) {
//if the remainder is less than half the grid size
if(position.left % this.options.grid < Math.round(this.options.grid / 2))
{
//lets round down
position.left -= position.left % this.options.grid;
}
else
{
//lets round up
position.left += this.options.grid - (position.left % this.options.grid);
}
//if the remainder is less than half the grid size
if(position.top % this.options.grid < Math.round(this.options.grid / 2))
{
//lets round down
position.top -= position.top % this.options.grid;
}
else
{
//lets round up
position.top += this.options.grid - (position.top % this.options.grid);
}
};
var _snapCalc = function(coords, position) {
$.parse(this.options.snap, $.bind(function(k, el) {
var snapCoords = el.trueCoordinates(),
detection = [{
left: {
min: snapCoords[0].left - this.options.snapDetection,
max: snapCoords[0].left + this.options.snapDetection},
top: {
min: snapCoords[0].top - this.options.snapDetection,
max: snapCoords[0].top + this.options.snapDetection}}, {
left: {
min: snapCoords[1].left - this.options.snapDetection,
max: snapCoords[1].left + this.options.snapDetection},
top: {
min: snapCoords[1].top - this.options.snapDetection,
max: snapCoords[1].top + this.options.snapDetection}
}];
var snappedHoriz = !$.parse([0,1], function(k, v) {
if(detection[0].left.min < coords[v].left && coords[v].left < detection[0].left.max)
{
//find the distance between the left and the snap coords left
position.left += snapCoords[0].left - coords[v].left;
//no need to iterate any more
return false;
}
if(detection[1].left.min < coords[v].left && coords[v].left < detection[1].left.max)
{
//find the distance between the left and the snap coords left
position.left += snapCoords[1].left - coords[v].left;
//no need to iterate any more
return false;
}
});
var snappedVert = !$.parse([0,1], function(k, v) {
if(detection[0].top.min < coords[v].top && coords[v].top < detection[0].top.max)
{
//find the distance between the left and the snap coords left
position.top += snapCoords[0].top - coords[v].top;
//no need to iterate any more
return false;
}
if(detection[1].top.min < coords[v].top && coords[v].top < detection[1].top.max)
{
//find the distance between the left and the snap coords left
position.top += snapCoords[1].top - coords[v].top;
//no need to iterate any more
return false;
}
});
//if we snapped
if(snappedHoriz || snappedVert)
{
//no need to iterate any more
return false;
}
}, this));
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
//unlisten
this.events.window.mouseup.off();
this.events.body.mouseup.off();
if($.BROWSER[0] == 'IE')
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
this.events.document.mousemove.off();
}
else
{
this.events.window.mousemove.off();
}
$.destroy(this);
//unmark on the element that there is a drag obj associated
this.target.freeSpace('draggable');
};
}, $.Base);
/* Interaction - Droppable Class
--------------------------------*/
$.def('Droppable', new function() {
this.CLASSNAME = 'Droppable';
/* Constructor
-------------------------------------*/
this.__construct = function(target, items, options) {
//track all the events
this.events = {};
this.options = options || {};
//set target
this.target = $.Element(target);
if(this.target.isSpace('droppable'))
{
this.target.getSpace('droppable').__destruct();
}
if(!(items instanceof Array))
{
items = [items];
}
$.parse(items, $.bind(function(key, el){
el = $.Element(el);
//set drag triggers
if(el.isSpace('draggable'))
{
$.setSpace(this.events, 'elements', key, 'stop', el.getSpace('draggable').on('stop', $.bind(this.drop, this)));
}
}, this));
this.target.setSpace('droppable', this);
};
/* Methods
-------------------------------------*/
this.drop = function(dragObj, e) {
if(this.trigger('drop', dragObj, this, e) === false)
{
return false;
}
//if the mouse was over the target while dragging
//lets append it to the target
var coords = this.target.trueCoordinates(),
mousePosition = $.mousePosition(e);
if(coords[0].left < mousePosition.left && coords[1].left > mousePosition.left &&
coords[0].top < mousePosition.top && coords[1].top > mousePosition.top)
{
//lets bring the real node back and destroy the proxy
if(this.options.type == 'margin')
{
dragObj.target.css('marginTop', dragObj.originalTargetStyle.marginTop);
dragObj.target.css('marginLeft', dragObj.originalTargetStyle.marginLeft);
}
else
{
dragObj.target.css('position', dragObj.originalTargetStyle.position);
dragObj.target.css('top', dragObj.originalTargetStyle.top);
dragObj.target.css('left', dragObj.originalTargetStyle.left);
}
dragObj.target.css('visibility', dragObj.originalTargetStyle.visibility);
if(dragObj.options.proxy === true || typeof dragObj.options.proxy == 'function')
{
//lets make a clone of the target node called a proxy
dragObj.removeProxy(dragObj.proxy);
}
this.target.append(dragObj.target);
return false;
}
};
/* Destructor
-------------------------------------*/
this.__destruct = function droppable_destroy() {
$.parse(this.events.elements, $.bind(function(key, evt) {
this.events.elements[key].stop.off();
}, this));
//unmark on the element that there is a drop obj associated
this.target.freeSpace('droppable');
$.destroy(this);
};
}, $.Base);
/* Interaction - Resizable Class
--------------------------------*/
$.def('Resizable', new function() {
this.CLASSNAME = 'Resizable';
/* Constructor
-------------------------------------*/
this.__construct = function (target, handles, options) {
//variable list
//track all binds
this.events = {};
//flag for dragging
this.resizing = false;
//set the target
this.target = $.Element(target);
//check if target has a draggable obj
if(this.target.isSpace('resizable'))
{
//lets destroy it
this.target.getSpace('resizable').__destruct();
}
//track original target style when the mousemove event is on
this.originalTargetStyle = {
display: this.target.css('display'),
visible: this.target.css('visible'),
height: this.target.css('height'),
width: this.target.css('width'),
marginLeft: this.target.css('marginLeft'),
marginTop: this.target.css('marginTop'),
position: this.target.css('position'),
top: this.target.css('top'),
left: this.target.css('left'),
visibility: this.target.css('visibility')};
var size = this.target.trueSize();
this.targetSizeOffset = {
width: size.width - parseInt(this.originalTargetStyle.width) || 0,
height: size.height - parseInt(this.originalTargetStyle.height) || 0};
//set the handles
this.handles = handles || {};
//listen to handles
$.parse(this.handles, $.bind(function(key, el) {
if(!el)
{
return;
}
this.handles[key] = $.Element(el);
$.setSpace(this.events, 'handle', key, 'mousedown', this.handles[key].on('mousedown', $.bind(this.start, this, key)));
}, this));
//set the options
this.options = options || {};
//set option defaults
this.options.snapDetection = this.options.snapDetection || 15;
//fix the snap option
if(this.options.snap)
{
//if string then it's a selector
//otherwise it can only be an element or Element
switch($.type(this.options.snap))
{
case 'array':
$.parse(this.options.snap, $.bind(function(k, v) {
this.options.snap[k] = $.Element(v);
}, this));
break;
case 'string':
this.options.snap = $.select(this.options.snap).get();
$.parse(this.options.snap, $.bind(function(k, v) {
this.options.snap[k] = $.Element(v);
}, this));
break;
case 'element':
this.options.snap = [$.Element(this.options.snap)];
break;
case 'Element':
this.options.snap = [this.options.snap];
break;
default:
this.options.snap = false;
break;
}
}
//mark on the element that there is a drag obj associated
this.target.setSpace('resizable', this);
};
/* Methods
-------------------------------------*/
this.start = function(e, direction) {
if(this.resizing)
{
return false;
}
this.resizing = true;
this.direction = direction;
//get the mouse position and target position
var mousePosition = $.mousePosition(e),
targetMargin = {left: parseInt(this.target.css('marginLeft')) || 0, top: parseInt(this.target.css('marginTop')) || 0},
targetPosition = {left: parseInt(this.target.css('left')) || 0, top: parseInt(this.target.css('top')) || 0},
coordinates = this.target.trueCoordinates();
this.init = {
position: mousePosition,
coords: coordinates,
offset: {
left: mousePosition.left - parseInt(coordinates[0].left),
top: mousePosition.top - parseInt(coordinates[0].top)},
relative: {
left: targetPosition.left,
top: targetPosition.top},
size: {
width: parseInt(this.target.css('width')) || coordinates[1].left - coordinates[0].left,
height: parseInt(this.target.css('height')) || coordinates[1].top - coordinates[0].top},
margin: {
left: targetMargin.left,
top: targetMargin.top}
};
//trigger
if(this.trigger('start', this, e, mousePosition, targetMargin, coordinates) === false)
{
return false;
}
//stop event
$.stop(e);
//listen to the window and body mouse up
$.setSpace(this.events, 'window', 'mouseup', $.Element(window).on('mouseup', $.bind(this.stop, this)));
$.setSpace(this.events, 'body', 'mouseup', $.Element(document.body).on('mouseup', $.bind(this.stop, this)));
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
if($.BROWSER[0] == 'IE')
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
$.setSpace(this.events, 'document', 'mousemove', $.Element(document).on('mousemove', $.bind(this.resize, this)));
}
else
{
$.setSpace(this.events, 'window', 'mousemove', $.Element(window).on('mousemove', $.bind(this.resize, this)));
}
if(this.options.proxy === true)
{
//lets make a clone of the target node called a proxy
this.proxy = this.getProxy(this.target);
}
else if(typeof this.options.proxy == 'function')
{
this.proxy = this.options.proxy(this.target);
}
else
{
this.proxy = this.target;
}
//setup the proxy to be draggable
if(this.options.type == 'margin')
{
this.proxy.css('marginLeft', targetMargin.left);
this.proxy.css('marginTop', targetMargin.top);
}
else
{
this.proxy.css('position', this.target.css('position') || 'relative');
this.proxy.css('left', targetPosition.left+'px');
this.proxy.css('top', targetPosition.top+'px');
}
//lets switch the proxy with the real element so the user wont know the difference
this.target.css('display', 'none');
this.proxy.css('display', 'block');
this.proxy.css('visibility', this.originalTargetStyle.visibility);
};
this.resize = function(e) {
//stop event
$.stop(e);
//set variables
var mousePosition = $.mousePosition(e),
proxyCoords = this.proxy.trueCoordinates(),
size = {
width: parseInt(this.proxy.css('width')) || 0,
height: parseInt(this.proxy.css('height')) || 0},
margin = {
left: parseInt(this.proxy.css('marginLeft')) || 0,
top: parseInt(this.proxy.css('marginTop')) || 0},
relative = {
left: parseInt(this.proxy.css('left')) || 0,
top: parseInt(this.proxy.css('top')) || 0},
diff = {
top: mousePosition.top - this.init.position.top,
left: mousePosition.left - this.init.position.left},
position = {
left: mousePosition.left - this.init.offset.left,
top: mousePosition.top - this.init.offset.top},
coords = $.clone(this.init.coords);
//if the mouse leaves the view port lets stop dragging
if(mousePosition.left < 2 || mousePosition.top < 2)
{
this.stop(e);
return;
}
//get the standard resize calculations
switch(true)
{
case this.direction.indexOf('n') != -1:
margin.top = this.init.margin.top + diff.top;
relative.top = this.init.relative.top + diff.top;
size.height = this.init.size.height - diff.top;
break;
case this.direction.indexOf('s') != -1:
size.height = this.init.size.height + diff.top;
break;
}
switch(true)
{
case this.direction.indexOf('w') != -1:
margin.left = this.init.margin.left + diff.left;
relative.left = this.init.relative.left + diff.left;
size.width = this.init.size.width - diff.left;
break;
case this.direction.indexOf('e') != -1:
size.width = this.init.size.width + diff.left;
break;
}
//validate width and height
size.width = size.width < 0 ? 0 : size.width;
size.height = size.height < 0 ? 0 : size.height;
//GRID OPTION CALCULATIONS
//if there is a grid lets do some epic math
if(typeof this.options.grid == 'number')
{
_gridCalc.call(this, size, this.options.type == 'margin' ? margin : relative);
}
//container and snap require for the
//coordinates to be calculated
//we want to do this after the grid calculations
//for accuracy
_coordCalc.call(this, size, coords, diff);
//SNAP OPTION CALCULATIONS
//if snap lets do some epic math
if(this.options.snap)
{
_snapCalc.call(this, size, coords, this.options.type == 'margin' ? margin : relative);
}
//CONTAINER OPTION CALCULATIONS
//if there are container and the target passes it then lets not drag
if(this.options.container)
{
var containerCoords = _getCoords.call(this, this.options.container);
var containerCoords = _getCoords.call(this, this.options.container);
if(coords[0].left < containerCoords[0].left)
{
relative.left += containerCoords[0].left - coords[0].left;
margin.left += containerCoords[0].left - coords[0].left;
}
else if(coords[1].left > containerCoords[1].left)
{
relative.left -= coords[1].left - containerCoords[1].left;
margin.left += containerCoords[0].left - coords[0].left;
}
if(coords[0].top < containerCoords[0].top)
{
relative.top += containerCoords[0].top - coords[0].top;
margin.left += containerCoords[0].left - coords[0].left;
}
if(coords[1].top > containerCoords[1].top)
{
relative.top -= coords[1].top - containerCoords[1].top;
margin.left += containerCoords[0].left - coords[0].left;
}
}
//MIN AND MAX OPTION CALCULATIONS
if(typeof this.options.minWidth == 'number' && size.width < this.options.minWidth)
{
return false;
}
if(typeof this.options.maxWidth == 'number' && size.width > this.options.maxWidth)
{
return false;
}
if(typeof this.options.minHeight == 'number' && size.height < this.options.minHeight)
{
return false;
}
if(typeof this.options.maxHeight == 'number' && size.height > this.options.maxHeight)
{
return false;
}
//trigger the resize
if(this.trigger('resize', this, e, coords, this.options.type == 'margin' ? margin : relative, size, diff) === false)
{
return false;
}
//now add the final calcs to the proxy
this.proxy.css('width', size.width+'px');
this.proxy.css('height', size.height+'px');
if(this.options.type == 'margin')
{
this.proxy.css('marginLeft', margin.left+'px');
this.proxy.css('marginTop', margin.top+'px');
}
else
{
this.proxy.css('left', relative.left+'px');
this.proxy.css('top', relative.top+'px');
}
};
this.stop = function(e) {
if(!this.resizing)
{
return;
}
this.resizing = false;
//unlisten
this.events.window.mouseup.off();
this.events.body.mouseup
if($.BROWSER[0] == 'IE')
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
this.events.document.mousemove.off();
}
else
{
this.events.window.mousemove.off();
}
if(this.trigger('stop', this, e) === false)
{
return false;
}
//lets bring the real node back and destroy the proxy
if(this.options.type == 'margin')
{
this.target.css('marginLeft', this.proxy.css('marginLeft'));
this.target.css('marginTop', this.proxy.css('marginTop'));
}
else
{
this.target.css('left', this.proxy.css('left'));
this.target.css('top', this.proxy.css('top'));
}
this.target.css('width', this.proxy.css('width'));
this.target.css('height', this.proxy.css('height'));
if(this.options.proxy === true || typeof this.options.proxy == 'function')
{
//lets make a clone of the target node called a proxy
this.removeProxy(this.proxy);
}
this.target.css('visibility', this.originalTargetStyle.visibility);
this.target.css('display', this.originalTargetStyle.display);
};
this.getProxy = function(target) {
var proxy = target.clone();
target.after(proxy);
return proxy;
};
this.removeProxy = function(proxy) {
proxy.remove();
return this;
};
/* Private Methods
-------------------------------------*/
var _getCoords = function (coords) {
if($.type(coords, 'array') &&
typeof coords[0].left == 'number' &&
typeof coords[0].top == 'number' &&
typeof coords[1].left == 'number' &&
typeof coords[1].top == 'number')
{
return coords;
}
else if($.type(coords, ['element', 'Element']))
{
return $.Element(coords).trueCoordinates();
}
coords = $.documentSize();
return [{left: 0, top: 0}, {left:coords.width, top: coords.height}];
};
var _gridCalc = function(size, margin) {
var grid = [];
switch(true)
{
case this.direction.indexOf('n') != -1:
grid.push([size, 'height']);
grid.push([margin, 'top']);
break;
case this.direction.indexOf('s') != -1:
grid.push([size, 'height']);
break;
}
switch(true)
{
case this.direction.indexOf('w') != -1:
grid.push([size, 'width']);
grid.push([margin, 'left']);
break;
case this.direction.indexOf('e') != -1:
grid.push([size, 'width']);
break;
}
$.parse(grid, $.bind(function(k, v) {
//if the remainder is less than half the grid size
if(v[0][v[1]] % this.options.grid < $.round(this.options.grid / 2))
{
//lets round down
v[0][v[1]] -= v[0][v[1]] % this.options.grid;
}
else
{
//lets round up
v[0][v[1]] += this.options.grid - (v[0][v[1]] % this.options.grid);
}
}, this));
};
var _coordCalc = function(size, coords, diff) {
switch(true)
{
case this.direction.indexOf('n') != -1:
coords[0].top += diff.top;
break;
case this.direction.indexOf('s') != -1:
coords[1].top = this.init.coords[0].top + size.height;
coords[1].top += this.targetSizeOffset.height;
break;
}
switch(true)
{
case this.direction.indexOf('w') != -1:
coords[0].left += diff.left;
break;
case this.direction.indexOf('e') != -1:
coords[1].left = this.init.coords[0].left + size.width;
coords[1].left += this.targetSizeOffset.width;
break;
}
};
var _snapCalc = function(size, coords, margin) {
$.parse(this.options.snap, $.bind(function(k, el) {
var snapCoords = el.trueCoordinates(),
detection = [{
left: {
min: snapCoords[0].left - this.options.snapDetection,
max: snapCoords[0].left + this.options.snapDetection},
top: {
min: snapCoords[0].top - this.options.snapDetection,
max: snapCoords[0].top + this.options.snapDetection}}, {
left: {
min: snapCoords[1].left - this.options.snapDetection,
max: snapCoords[1].left + this.options.snapDetection},
top: {
min: snapCoords[1].top - this.options.snapDetection,
max: snapCoords[1].top + this.options.snapDetection}}];
var snappedHoriz = !$.parse([0,1], $.bind(function(k, v) {
if(detection[0].left.min < coords[v].left && coords[v].left < detection[0].left.max)
{
//find the distance between the left and the snap coords left
switch(true)
{
case this.direction.indexOf('w') != -1:
margin.left += snapCoords[0].left - coords[v].left;
size.width -= snapCoords[0].left - coords[v].left;
break;
case this.direction.indexOf('e') != -1:
size.width += snapCoords[0].left - coords[v].left;
break;
}
}
else if(detection[1].left.min < coords[v].left && coords[v].left < detection[1].left.max)
{
//find the distance between the left and the snap coords left
switch(true)
{
case this.direction.indexOf('w') != -1:
margin.left += snapCoords[1].left - coords[v].left;
size.width -= snapCoords[1].left - coords[v].left;
break;
case this.direction.indexOf('e') != -1:
size.width += snapCoords[1].left - coords[v].left;
break;
}
}
}, this));
var snappedVert = !$.parse([0,1], $.bind(function(k, v) {
if(detection[0].top.min < coords[v].top && coords[v].top < detection[0].top.max)
{
//find the distance between the left and the snap coords left
switch(true)
{
case this.direction.indexOf('n') != -1:
margin.top += snapCoords[0].top - coords[v].top;
size.height -= snapCoords[0].top - coords[v].top;
break;
case this.direction.indexOf('s') != -1:
size.height += snapCoords[0].top - coords[v].top;
break;
}
}
else if(detection[1].top.min < coords[v].top && coords[v].top < detection[1].top.max)
{
//find the distance between the left and the snap coords left
switch(true)
{
case this.direction.indexOf('n') != -1:
margin.top += snapCoords[1].top - coords[v].top;
size.height -= snapCoords[1].top - coords[v].top;
break;
case this.direction.indexOf('s') != -1:
size.height += snapCoords[1].top - coords[v].top;
break;
}
}
}, this));
//if we snapped
if(snappedHoriz || snappedVert)
{
//no need to iterate any more
return false;
}
}, this));
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
//unlisten
try
{
this.events.window.mouseup.off();
this.events.body.mouseup.off();
if($.BROWSER[0] == 'IE')
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
this.events.document.mousemove.off();
}
else
{
this.events.window.mousemove.off();
}
} catch(e) {}
$.parse(this.events.handle, $.bind(function(key, evt) {
this.events.handle[key].mousedown.off();
}, this));
//unmark on the element that there is a resize obj associated
this.target.freeSpace('resizable');
$.destroy(this);
};
}, $.Base);
/* Interaction - Sortable Class
--------------------------------*/
$.def('Sortable', new function() {
this.CLASSNAME = 'Sortable';
/* Constructor
-------------------------------------*/
this.__construct = function(target, options) {
this.events = {};
this.target = $.Element(target);
if(this.target.isSpace('sortable'))
{
this.target.getSpace('sortable').__destruct();
}
this.draggables = [];
this.elements = [];
this.options = $.combine({direction: 'all', tree: false}, options || {});
switch($.type(this.options.items))
{
case 'string':
//assume is selector
this.options.items = $.select(this.options.items, this.target).get();
break;
case 'Element':
case 'element':
this.options.items = [$.Element(this.options.items)];
break;
case 'array':
this.options.items = this.options.items;
break;
default:
this.options.items = [];
}
$.parse(this.options.items, $.bind(function(key, el){
this.add(el);
}, this));
this.target.setSpace('sortable', this);
};
/* Methods
-------------------------------------*/
this.add = function(el) {
el = $.Element(el);
this.elements.push(el);
var key = this.elements.length - 1;
//make draggable
if(!el.isSpace('draggable'))
{
$.Draggable(el, {direction: this.options.direction});
this.draggables.push(el);
}
$.setSpace(this.events, 'elements', key, 'start', el.getSpace('draggable').on('start', $.bind(this.start, this)));
$.setSpace(this.events, 'elements', key, 'start', el.getSpace('draggable').on('drag', $.bind(this.arrange, this)));
$.setSpace(this.events, 'elements', key, 'start', el.getSpace('draggable').on('stop', $.bind(this.stop, this)));
};
this.start = function(dragObj, e) {
//trigger
if(this.trigger('start', dragObj, this, e) === false)
{
return false;
}
$.stop(e);
if(typeof dragObj.options.proxy == 'function')
{
dragObj.proxy = dragObj.options.proxy(dragObj.target);
}
else
{
//lets make a clone of the target node called a proxy
dragObj.proxy = dragObj.getProxy(dragObj.target);
}
if(dragObj.options.type == 'margin')
{
dragObj.proxy.css('marginLeft', dragObj.target.css('marginLeft') || 0);
dragObj.proxy.css('marginTop', dragObj.target.css('marginTop') || 0);
var proxyCoords = dragObj.proxy.trueCoordinates();
targetCoords = dragObj.target.trueCoordinates();
dragObj.proxy.css('marginLeft', (targetCoords[0].left - proxyCoords[0].left)+'px');
dragObj.proxy.css('marginTop', (targetCoords[0].top - proxyCoords[0].top)+'px');
}
else
{
dragObj.proxy.css('position', 'absolute');
dragObj.proxy.css('left', (parseInt(dragObj.target.css('left')) || 0)+'px' || 0);
dragObj.proxy.css('top', (parseInt(dragObj.target.css('top')) || 0)+'px' || 0);
var proxyCoords = dragObj.proxy.trueCoordinates();
targetCoords = dragObj.target.trueCoordinates();
dragObj.proxy.css('left', (targetCoords[0].left - proxyCoords[0].left)+'px');
dragObj.proxy.css('top', (targetCoords[0].top - proxyCoords[0].top)+'px');
}
//lets switch the proxy with the real element so the user wont know the difference
dragObj.target.css('visibility', 'hidden');
dragObj.proxy.css('display', 'block');
dragObj.proxy.css('visibility', dragObj.originalTargetStyle.visibility);
//get the mouse position and target position
var mousePosition = $.mousePosition(e),
coordinates = dragObj.proxy.trueCoordinates();
//we need to redo the init
dragObj.init = {
mouse: mousePosition,
position: {
left: mousePosition.left - parseInt(coordinates[0].left),
top: mousePosition.top - parseInt(coordinates[0].top)},
relative: {
left: mousePosition.left - (parseInt(dragObj.proxy.css('left')) || 0),
top: mousePosition.top - (parseInt(dragObj.proxy.css('top'))||0)},
margin: {
left: mousePosition.left - (parseInt(dragObj.proxy.css('marginLeft')) || 0),
top: mousePosition.top - (parseInt(dragObj.proxy.css('marginTop')) || 0)}};
return false;
};
this.arrange = function(dragObj, e, position) {
if(this.trigger('sort', dragObj, this, e) === false)
{
return false;
}
//if the mouse was over the target while dragging
//lets append it to the target
var dragObjCoords = dragObj.proxy.trueCoordinates(), dragTargetCoords = dragObj.target.trueCoordinates(), mousePosition = $.mousePosition(e);
//check the current element
if(dragTargetCoords[0].left < mousePosition.left && dragTargetCoords[1].left > mousePosition.left &&
dragTargetCoords[0].top < mousePosition.top && dragTargetCoords[1].top > mousePosition.top)
{
return;
}
$.rparse(this.elements, function(key, el) {
el = $.Element(el);
var coords = el.trueCoordinates();
if(coords[0].left < mousePosition.left && coords[1].left > mousePosition.left &&
coords[0].top < mousePosition.top && coords[1].top > mousePosition.top)
{
//if the current drag is a child of this element
//and the current drag has a previous
if(dragObj.target.childOf(el) && dragObj.target.previous())
{
return true;
}
//given: coordinates of element in question and mouse coords
//find: x on the hypontenuse
//see: "law of cosine" and "law of sine"
//get all the sides
var sideA = coords[1].left - coords[0].left,
sideB = coords[1].top - coords[0].top,
sideC = $.hypotenuse(sideA, sideB),
//get all the angles
angleA = $.trigSSS(sideA, sideB, sideC),
angleB = $.trigSSS(sideB, sideA, sideC),
//find the difference between top el coord and mouse top
newSideB = mousePosition.top - coords[0].top,
//a = b*sin[A]/sin[B] = 4*.90631/.42262 = 8.5780
//c = b*sin[C]/sin[B] = 4*1/.42262 = 9.4648
newSideA = newSideB * Math.sin(angleB) / Math.sin(angleA),
x = coords[1].left - newSideA;
$.createElement('div', {}, null, document.body).css({position:'absolute', background:'red', height:'2px', width:'2px'}).css('top', (coords[1].top - newSideB)+'px').css('left', x+'px');
console.log(angleA+' '+angleB);
//if the mouse is before the x threshold
if(mousePosition.left < x)
{
//if there is a next and the next is the current element
if(dragObj.target.next() && dragObj.target.next().uid() == el.uid())
{
//we can end it here
return false;
}
el.before(dragObj.target);
return false;
}
el.after(dragObj.target);
return false;
}
});
};
this.stop = function(dragObj, e) {
if(this.trigger('stop', dragObj, this, e) === false)
{
return false;
}
$.stop(e);
//if the mouse was over the target while dragging
//lets append it to the target
var coords = this.target.trueCoordinates(), mousePosition = $.mousePosition(e);
dragObj.target.css('visibility', dragObj.originalTargetStyle.visibility);
dragObj.target.css('display', dragObj.originalTargetStyle.display);
dragObj.target.css('position', '');
dragObj.target.css('top', '');
dragObj.target.css('left', '');
dragObj.proxy.remove();
//unlisten
dragObj.events.window.mouseup.off();
dragObj.events.body.mouseup.off();
if($.BROWSER[0] == 'IE')
{
//start observing the mouse movement
//also keep track of this event so later we can stop listening;
dragObj.events.document.mousemove.off();
}
else
{
dragObj.events.window.mousemove.off();
}
//lets undo what startDrag has initialized
return false;
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
//unlisten to all drop event
$.parse(this.events.items, $.bind(function(key, evt) {
this.events.items[key].start.off();
this.events.items[key].drag.off();
this.events.items[key].stop.off();
}, this));
//if a draggable was created lets destruct it
$.parse(this.draggables, function(k, el) {
el.getSpace('draggable').__destruct();
});
//remove the sortable object from the target
this.target.freeSpace('sortable');
//destroy this class instance
$.destroy(this);
};
}, $.Base);
/* Accordian - Marquee Class
--------------------------------*/
$.def('Accordian', new function() {
this.CLASSNAME = 'Accordian';
/* Constructor
-------------------------------------*/
this.__construct = function (target, options) {
this.target = $.Element(target);
this.events = {};
this.items = [];
this.active = {};
this.options = $.combine({
direction: 'vertical',
showAll: true,
hideAll: true
}, options || {});
switch($.type(this.options.items))
{
case 'array':
this.options.items = this.options.items;
break;
default:
this.options.items = [];
break;
}
$.parse(this.options.items, $.bind(function(key, args) {
this.add.apply(this, args);
}, this));
};
/* Setter Methods
-------------------------------------*/
this.add = function(trigger, target, options) {
trigger = $.Element(trigger);
target = $.Element(target);
//set default options
options = $.combine({
bindActive: 'click',
show: false,
height: false
}, options);
if(!options.height)
{
options.height = target.trueSize().height;
target.css('overflow', 'hidden');
}
//add it to the store
this.items.push([trigger, target, options]);
var id = this.items.length - 1;
if(options.show === false)
{
this.hide(id);
}
else
{
this.show(id);
}
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('add', this, id) === false)
{
return false;
}
//store this bind method
$.setSpace(this.events, 'items', id, options.bindActive, trigger.on(options.bindActive, $.bind(_eventToggle, this, id)));
return this;
};
this.show = function(id) {
var i = this.items[id];
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('show', this, id) === false)
{
return false;
}
if(this.active[id] === true)
{
i[1].css('display', 'none');
this.active[id] = false;
return this;
}
this.active[id] = true;
i[1].css('display', 'block');
if(i[2].height)
{
i[1].tween({height: [0+'px', parseInt(i[2].height)+'px']});
}
};
this.hide = function(id) {
var i = this.items[id];
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('hide', this, id) === false)
{
return false;
}
if(this.active[id] == false)
{
i[1].css('display', 'none');
return this;
}
this.active[id] = false;
if(i[2].height)
{
i[1].tween({height: [parseInt(i[2].height)+'px', 0+'px']}, function() {
i[1].css('display', 'none');
});
}
else
{
i[1].css('display', 'none');
}
};
this.toggle = function(id) {
var i = this.items[id];
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('toggle', this, id) === false)
{
return false;
}
if(!this.options.showAll)
{
$.parse(this.active, $.bind(function(key, active) {
if(active && key != id)
{
this.hide(key);
}
}, this));
if(this.options.showOne && this.active[id])
{
return this;
}
}
if(!this.options.hideAll)
{
var oneIsActive = $.parse(this.active, $.bind(function(key, active) {
if(active)
{
return false;
}
}, this));
if(!oneIsActive && this.active[id])
{
return this;
}
}
if(i[1].css('display') == 'none')
{
this.show(id);
}
else
{
this.hide(id);
}
return this;
};
/* Private Methods
-------------------------------------*/
var _eventToggle = function(e, id) {
$.stop(e);
this.toggle(id);
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
//for each tab, off
if($.isSpace(this.events, 'items'))
{
$.parse($.getSpace(this.events, 'items'), $.bind(function(id, evt) {
evt[this.tabs[id][2].bindActive].off();
}, this));
}
$.destroy(this);
};
}, $.Base);
/* Widget - Box Class
--------------------------------*/
$.def('Box', new function() {
this.CLASSNAME = 'Box';
/* Constructor
-------------------------------------*/
this.__construct = function (target, options) {
this.dragObj = null;
this.resizeObj = null;
this.events = {};
if($.type(target, 'string') && !$.validAlphaNum(target))
{
this.target = $.toElement(target);
}
else
{
this.target = $.Element(target);
}
this.options = $.combine({
head: null, body: null,
foot: null, close: null,
draggable: null, resizable: null,
append: $.Element(document.body)
}, options);
//handle dragging
if(this.options.draggable)
{
if($.type(this.options.draggable, 'object'))
{
this.dragObj = $.Draggable(this.target, this.options.draggable);
}
else
{
this.dragObj = $.Draggable(this.target);
}
$.setSpace(this.events, 'drag', 'start', this.dragObj.on('start', $.bind(this.dragStart, this)));
$.setSpace(this.events, 'drag', 'drag', this.dragObj.on('drag', $.bind(this.drag, this)));
$.setSpace(this.events, 'drag', 'stop', this.dragObj.on('stop', $.bind(this.dragStop, this)));
}
//handle resizable
if($.type(this.options.resizable, 'object') && $.type(this.options.resizable.handles, 'object'))
{
if($.type(this.options.resizable.options, 'object'))
{
this.resizeObj = $.Resizable(
this.target,
this.options.resizable.handles,
this.options.resizable.options);
}
else
{
this.resizeObj = $.Resizable(
this.target,
this.options.resizable.handles);
}
$.setSpace(this.events, 'resize', 'start', this.resizeObj.on('start', $.bind(this.resizeStart, this)));
$.setSpace(this.events, 'resize', 'resize', this.resizeObj.on('resize', $.bind(this.resize, this)));
$.setSpace(this.events, 'resize', 'stop', this.resizeObj.on('stop', $.bind(this.resizeStop, this)));
}
//handle close node
if(this.options.close)
{
$.setSpace(this.events, 'close', 'click', $.Element(this.options.close).on('click', $.bind(this.close, this)));
}
};
/* Setter Methods
-------------------------------------*/
this.setHead = function(html) {
if(this.options.head)
{
switch($.type(html))
{
case 'string':
$.Element(this.options.head).html(html);
break;
case 'Element':
case 'element':
$.Element(this.options.head).html('');
$.Element(this.options.head).append(html);
break;
}
}
return this;
};
this.setBody = function(html) {
if(this.options.body)
{
switch($.type(html))
{
case 'string':
$.Element(this.options.body).html(html);
break;
case 'Element':
case 'element':
$.Element(this.options.body).html('');
$.Element(this.options.body).append(html);
break;
}
}
return this;
};
this.setFoot = function(html) {
if(this.options.foot)
{
switch($.type(html))
{
case 'string':
$.Element(this.options.foot).html(html);
break;
case 'Element':
case 'element':
$.Element(this.options.foot).html('');
$.Element(this.options.foot).append(html);
break;
}
}
return this;
};
/* Event Methods
-------------------------------------*/
this.dragStart = function(scope, e, margin ) {
return this.trigger('dragStart', scope, e, margin);
};
this.drag = function(scope, e, margin) {
return this.trigger('drag', scope, e, margin);
};
this.dragStop = function(scope, e) {
return this.trigger('dragStop', scope, e);
};
this.resizeStart = function(scope, e, mousePosition, targetMargin, targetPosition) {
return this.trigger('resizeStart', scope, e, mousePosition, targetMargin, targetPosition);
};
this.resize = function(scope, e, coords, margin, size) {
return this.trigger('resize', scope, e, coords, margin, size);
};
this.resizeStop = function(scope, e) {
return this.trigger('resizeStop', scope, e);
};
this.open = function(trigger) {
trigger = !(trigger === false);
if(trigger && this.trigger('open', this) === false)
{
return false;
}
this.options.append.append(this.target);
this.target.css('display', 'block');
return this;
};
this.close = function(trigger) {
trigger = !(trigger === false);
if(trigger && this.trigger('close', this) === false)
{
return false;
}
this.target.remove();
return this;
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
if(this.dragObj)
{
this.events.drag.start.off();
this.events.drag.drag.off();
this.events.drag.stop.off();
this.dragObj.__destruct();
}
if(this.resizeObj)
{
this.events.resize.start.off();
this.events.resize.resize.off();
this.events.resize.stop.off();
this.resizeObj.__destruct();
}
if(this.options.close)
{
$.Element(this.options.close).unbind('click', this.events.close.click);
}
$.destroy(this);
};
}, $.Base);
/* Widget - Dialog Class
--------------------------------*/
$.def('Dialog', new function() {
this.CLASSNAME = 'Dialog';
/* Constructor
-------------------------------------*/
this.__construct = function (target, options) {
this.__parent.__construct.call(this, target, options);
this.options = $.combine({
modal: true, fixed: true,
zIndex: 9998
}, this.options || {});
//set the target zIndex
if(this.options.zIndex)
{
this.target.css('zIndex', this.options.zIndex)
}
if(this.options.modal)
{
//build a modal
this.options.modal = _modal.call(this, this.options.modal, this.options.zIndex);
//listen to click
if(this.options.closeOnModalClick)
{
$.setSpace(this.events, 'modal', 'click', $.Element(this.options.modal).on('click', $.bind(this.close, this)));
}
}
//set fixed
if(this.options.fixed)
{
//center the target
_center.call(this, this.target);
//listen to resize
$.setSpace(this.events, 'window', 'scroll', $.Element(window).on('scroll', $.bind(_scroll, this)));
$.setSpace(this.events, 'resize', 'resizeStop', this.on('resizeStop', $.bind(_resizeStop, this)));
}
if($.BROWSER[0] == 'IE' && $.BROWSER[1] == 6)
{
this.IEfix = $.createElement('iframe');
}
$.setSpace(this.events, 'window', 'resize', $.Element(window).on('resize', $.bind(_fix, this)));
};
/* Public Methods
-------------------------------------*/
this.open = function() {
//call parent open no trigger
this.__parent.open.call(this, false);
if(this.options.modal)
{
//stetch the modal over the document
_cover.call(this, this.options.modal);
if(this.IEfix)
{
this.IEfix.css({
position: 'absolute',
top: this.options.modal.css('top'), left: this.options.modal.css('left'),
width: this.options.modal.css('width'), height: this.options.modal.css('height'),
opacity: '0', filter: 'alpha(opacity=0)'
});
//insert the modal before the target
this.target.before(this.IEfix);
}
//insert the modal before the target
this.target.before(this.options.modal);
}
_center.call(this, this.target);
if(this.__parent.open.call(this) === false)
{
return false;
}
return this;
};
this.close = function() {
if(this.__parent.close.call(this) === false)
{
return false;
}
if(this.options.modal)
{
this.options.modal.remove();
if(this.IEfix)
{
this.options.IEfix.remove();
}
}
return this;
};
/* Private Methods
-------------------------------------*/
var _center = function(node) {
var windowCenter = $.windowCenter(),
windowOffset = $.windowOffset(),
size = node.trueSize();
node.css({
position: 'relative',
margin: 0,
top: (windowCenter.top + windowOffset.top - (size.height / 2))+'px',
left: (windowCenter.left + windowOffset.left - (size.width / 2))+'px'
});
return this;
};
var _cover = function(node) {
node.css('display', 'none');
//get the screen size
var documentSize = $.documentSize();
node.css({
position: 'absolute',
top: 0, left: 0,
width: documentSize.width+'px', height: documentSize.height+'px'
});
node.css('display', '');
return this;
};
var _fix = function(e) {
if(this.options.fixed)
{
_center.call(this, this.target);
}
if($.type(this.options.modal, ['element', 'Element']))
{
_cover.call(this, this.options.modal);
}
return this;
};
var _modal = function(modal, zIndex) {
switch($.type(modal))
{
case 'boolean':
if(modal === true)
{
modal = $.createElement('div', {id: 'model'}).css({
zIndex: zIndex, background: '#000',
opacity: '.4', filter: 'alpha(opacity=40)'
});
}
break;
case 'string':
case 'element':
case 'Element':
modal = $.Element(modal);
break;
default:
return null;
}
modal = !!(modal) ? modal : $.createElement('div', {id: 'model'}).css({
zIndex: zIndex, background: '#000',
opacity: '.4', filter: 'alpha(opacity=40)'
});
return modal;
};
var _resizeStop = function(resize) {
//lets bring the real node back and destroy the proxy
resize.target.css('width', resize.proxy.css('width'));
resize.target.css('height', resize.proxy.css('height'));
resize.proxy.remove();
resize.target.css('display', resize.originalTargetStyle.display);
_center.call(this, this.target);
return false;
};
var _scroll = function(e) {
var original = this.target.css('display');
this.target.css('display', 'none');
_center.call(this, this.target);
this.target.css('display', original);
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
if(this.options.modal)
{
this.events.modal.click.off();
}
this.events.window.resize.off();
this.__parent.__destruct.call(this);
};
}, $.Box.prototype);
/* Widget - Marquee Class
--------------------------------*/
$.def('Marquee', new function() {
this.CLASSNAME = 'Menu';
/* Constructor
-------------------------------------*/
this.__construct = function (target, container, options) {
this.target = $.Element(target);
this.container = $.Element(container);
this.events = {};
this.options = $.combine({
draggable: false,
direction: 'all',
handles: {}
}, options || {});
if(this.options.draggable === true)
{
this.options.draggable = $.Draggable(this.target, {direction: this.options.direction}).on('drag', $.bind(_eventDrag, this));
}
//set the handles
this.options.handles = this.options.handles || {};
//listen to handles
$.parse(this.options.handles, $.bind(function(key, el) {
if(!el)
{
return;
}
this.options.handles[key] = $.Element(el);
$.setSpace(this.events, 'handle', key, 'click', this.options.handles[key].on('click', $.bind(this.scroll, this, key)));
}, this));
};
/* Setter Methods
-------------------------------------*/
this.scroll = function(e, direction) {
var position = {
left: parseInt(this.target.css('left')) || 0,
top: parseInt(this.target.css('top')) || 0},
targetSize = this.target.trueSize(),
containerSize = this.container.trueSize(),
origPosition = $.clone(position);
//get the standard resize calculations
if(targetSize.height > containerSize.height)
{
switch(true)
{
case direction.indexOf('n') != -1:
position.top += containerSize.height;
break;
case direction.indexOf('s') != -1:
position.top -= containerSize.height;
break;
}
if(position.top > 0)
{
position.top = 0;
}
var maxTop = -1 * (targetSize.height - containerSize.height);
if(position.top < maxTop)
{
position.top = maxTop;
}
}
if(targetSize.width > containerSize.width)
{
switch(true)
{
case direction.indexOf('w') != -1:
position.left += containerSize.width;
break;
case direction.indexOf('e') != -1:
position.left -= containerSize.width;
break;
}
//validate max scroll and min scroll
if(position.left > 0)
{
position.left = 0;
}
var maxLeft = -1 * (targetSize.width - containerSize.width);
if(position.left < maxLeft)
{
position.left = maxLeft;
}
}
if(this.trigger('scroll', this, position, direction) === false)
{
return false;
}
this.target.tween({
left: [origPosition.left+'px', position.left+'px'],
top: [origPosition.top+'px', position.top+'px']
}, 100);
};
/* Private Methods
-------------------------------------*/
var _eventDrag = function(dragObj, e, position) {
_fixPosition.call(this, position);
};
var _fixPosition = function(position) {
//validate max scroll and min scroll
if(position.left > 0)
{
position.left = 0;
}
if(position.top > 0)
{
position.top = 0;
}
var targetSize = this.target.trueSize();
var containerSize = this.container.trueSize();
var maxTop = -1 * (targetSize.height - containerSize.height);
var maxLeft = -1 * (targetSize.width - containerSize.width);
if(position.left < maxLeft)
{
position.left = maxLeft;
}
if(position.top < maxTop)
{
position.top = maxTop;
}
return position;
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
$.destroy(this);
};
}, $.Base);
/* Widget - Menu Class
--------------------------------*/
$.def('Menu', new function() {
this.CLASSNAME = 'Menu';
/* Constructor
-------------------------------------*/
this.__construct = function (target, options) {
this.events = {};
this.target = $.Element(target);
this.items = [];
//set up the options
this.options = $.combine({hoverClass: 'hover'}, options || {});
switch($.type(this.options.items))
{
case 'string':
//assume is selector
this.options.items = $.select(this.options.items, this.target).get();
break;
case 'Element':
case 'element':
this.options.items = [$.Element(this.options.items)];
break;
case 'array':
this.options.items = this.options.items;
break;
default:
this.options.items = [];
}
$.parse(this.options.items, $.bind(function(key, el){
this.add(el);
}, this));
};
/* Setter Methods
-------------------------------------*/
this.add = function(el) {
el = $.Element(el);
this.items.push(el);
id = this.items.length -1;
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('add', this, id) === false)
{
return false;
}
//start listening to events
$.setSpace(this.events, 'items', id, 'mouseover', el.on('mouseover', $.bind(this.show, this, el)));
$.setSpace(this.events, 'items', id, 'mouseout', el.on('mouseout', $.bind(this.hide, this, el)));
$.setSpace(this.events, 'items', id, 'click', el.on('click', $.bind(this.run, this, el)));
};
this.show = function(e, el) {
//trigger
if(this.trigger('show', this, e, el) === false)
{
return false;
}
$.stop(e);
el.addClass(this.options.hoverClass);
var parents = el.parents();
//pop out the body
parents.pop();
parents.parse($.bind(function(i, el) {
//get the id
var uid = el.uid();
$.parse(this.items, $.bind(function(j, el2) {
if(el2.uid() == uid)
{
el.addClass(this.options.hoverClass);
return false;
}
}, this));
}, this))
return this;
};
this.hide = function(e, el) {
//trigger
if(this.trigger('hide', this, e, el) === false)
{
return false;
}
$.stop(e);
el.removeClass(this.options.hoverClass);
var parents = el.parents();
//pop out the body
parents.pop();
parents.parse($.bind(function(i, el) {
//get the id
var uid = el.uid();
$.parse(this.items, $.bind(function(j, el2) {
if(el2.uid() == uid)
{
el.removeClass(this.options.hoverClass);
return false;
}
}, this));
}, this))
return this;
};
this.run = function(e, el) {
$.stop(e);
//trigger
if(this.trigger('run', this, el) === false)
{
return false;
}
this.hide(e, el);
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
//unlisten to all drop event
$.parse(this.events.items, $.bind(function(key, evt) {
this.events.items[key].mouseover.off();
this.events.items[key].mouseout.off();
this.events.items[key].click.off();
}, this));
$.destroy(this);
};
}, $.Base);
/* Widget - Tabs Class
--------------------------------*/
$.def('Tabs', new function() {
this.CLASSNAME = 'Tabs';
/* Constructor
-------------------------------------*/
this.__construct = function (options) {
//this is our event bind manager
//we need this to successfully unbind events
this.events = {};
//this will act like a store for tabs
this.tabs = [];
//whenever a tab is removed it will make this tab active
this.defaultTab = 0;
//this will be used to track the active tab incase we need
//to make it inactive
this.activeTab = null;
//set default options
this.options = $.combine({
close: false, //the element on click will close
sortable: false
}, options);
this.options.close = $.Element(this.options.close);
switch($.type(this.options.items))
{
case 'array':
this.options.items = this.options.items;
break;
default:
this.options.items = [];
break;
}
$.parse(this.options.items, $.bind(function(key, args){
this.add.apply(this, args);
}, this));
//if close tab, onclick close the active tab
if($.type(this.options.close, 'Element'))
{
$.setSpace(this.events, 'close', 'click', this.options.close.on('click', $.bind(_eventRemove, this)));
}
if(this.options.sortable instanceof Array)
{
this.sortable = $.Sortable.apply($.Sortable, this.options.sortable);
$.setSpace(this.events, 'sortable', 'stop', this.sortable.on('stop', $.bind(_eventStop, this)));
$.setSpace(this.events, 'sortable', 'start', this.sortable.on('start', $.bind(_eventStart, this)));
}
};
/* Setter Methods
-------------------------------------*/
this.add = function(tab, target, options) {
tab = $.Element(tab);
target = $.Element(target);
//set default options
options = $.combine({
defaultTab: true, //whether to set this as active
bindActive: 'click',
activeClass: null,
active: true,
append: false
}, options);
//add it to the store
this.tabs.push([tab, target, options]);
var id = this.tabs.length - 1;
//set the defaultTab if option.defaultTab is true
if(options.defaultTab)
{
this.defaultTab = id;
}
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('add', this, id) === false)
{
return false;
}
//store this bind method
$.setSpace(this.events, 'tab', id, options.bindActive, tab.on(options.bindActive, $.bind(_eventActive, this, id)));
//add to sortable
if(this.sortable)
{
tab.setSpace('TabSortableId', id);
this.sortable.add(tab);
}
if(options.active)
{
this.active(id);
}
return this;
};
this.remove = function(id) {
//get the tab
var tab = this.tabs[id];
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('remove', this, id) === false)
{
return false;
}
//get the bound callback and unbind this
$.getSpace(this.events, 'tab', id, tab[2].bindActive).off();
//remove
tab[0].remove();
tab[1].remove();
if(this.tabs.length > 0)
{
if(this.defaultTab == this.activeTab)
{
this.defaultTab = 0;
}
this.active(this.defaultTab);
}
return this;
};
this.active = function(id) {
//get the tab
var tab = this.tabs[id];
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('active', this, id) === false)
{
return false;
}
//set current active tab as inactive
if(typeof this.activeTab == 'number')
{
this.inactive(this.activeTab);
}
//set this to active
if(tab[2].activeClass)
{
tab[0].addClass(tab[2].activeClass);
}
tab[1].css('display', 'block');
//if they want to append this somewhere
if($.type(tab[2].append, ['Element', 'element']))
{
$.Element(tab[2].append).append(tab[1]);
}
//Flag this active flag now
this.activeTab = id;
return this;
};
this.inactive = function(id) {
//get the tab
var tab = this.tabs[id];
//trigger before any actual changes to the dom occurs
//we do this to allow the end developer to customize the outcome
if(this.trigger('inactive', this, id) === false)
{
return false;
}
//set tab as inactive
if(tab[2].activeClass)
{
tab[0].removeClass(tab[2].activeClass);
}
tab[1].css('display', 'none');
return this;
};
/* Private Methods
-------------------------------------*/
var _eventRemove = function(e) {
$.stop(e);
if(typeof this.activeTab == 'number')
{
this.remove(this.activeTab);
}
};
var _eventActive = function(e, id) {
$.stop(e);
this.active(id);
};
var _eventStart = function(dragObj, sortObj, e) {
this.mouseDown = false;
setTimeout($.bind(function() {
this.mouseDown = true;
}, this), 350);
};
var _eventStop = function(dragObj, sortObj, e) {
var id = $.Element(dragObj.target).getSpace('TabSortableId');
if(typeof id == 'number')
{
if(!this.mouseDown)
{
this.active(id);
}
}
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
$.parse(this.tabs, $.bind(function(id, tab) {
tab.freeSpace('TabSortableId');
}, this));
//if close tab, off
if($.isSpace(this.events, 'close', 'click'))
{
$.getSpace(this.events, 'close', 'click').off();
}
//for each tab, off
if($.isSpace(this.events, 'tab'))
{
$.parse($.getSpace(this.events, 'tab'), $.bind(function(id, evt) {
evt[this.tabs[id][2].bindActive].off();
}, this));
}
if($.isSpace(this.events, 'sortable', 'stop'))
{
this.events.sortable.stop.off();
}
$.destroy(this);
};
}, $.Base);
/* Widget - Tooltip Class
--------------------------------*/
$.def('Tooltip', new function() {
this.CLASSNAME = 'Tooltip';
/* Constructor
-------------------------------------*/
this.__construct = function (target, options) {
options = $.combine({
body: target //set a body
}, options || {});
this.__parent.__construct.call(this, target, options);
this.events = {};
this.tooltips = [];
this.options = $.combine({
showDelay: 0,//timeout before showing tooltip
hideDelay: 0,//timeout before hiding tooltip
autohide: false,//flag to hide tooltip after hideDelay has been reached
followMouse: false//tooltip follows mouse
}, this.options || {});
if($.BROWSER[0] == 'IE' && $.BROWSER[1] == 6)
{
this.IEfix = $.createElement('iframe');
}
this.target.css('position', 'relative');
};
/* Public Methods
-------------------------------------*/
this.add = function(trigger, target, options) {
options = $.combine({
bindShow: 'mouseover',//event to listen to on the target to show tooltip
bindHide: 'mouseout',//event to listen to on the target to hide tooltip
position: 'mouse',//initial position; 'top','bottom','left','right','mouse'
zIndex: 'auto',
offsetLeft: 0,
offsetTop: 0
}, options || {});
//push it into the stack
this.tooltips.push([$.Element(trigger), $.Element(target), options, false]);
//so this way we can get an ID
var id = this.tooltips.length-1;
//listen to the trigger
$.setSpace(this.events, 'tooltip', id, options.bindShow, $.Element(trigger).on(options.bindShow, $.bind(this.open, this, id)));
$.setSpace(this.events, 'tooltip', id, options.bindHide, $.Element(trigger).on(options.bindHide, $.bind(this.close, this, id)));
$.setSpace(this.events, 'target', id, options.bindHide, $.Element(this.target).on(options.bindHide, $.bind(this.close, this, id)));
//return the id incase they want to remove it later
return id;
};
this.remove = function(id) {
$.getSpace(this.events, 'tooltip', id, this.tooltips[id][2].bindShow).off();
$.getSpace(this.events, 'tooltip', id, this.tooltips[id][2].bindHide).off();
$.getSpace(this.events, 'target', id, this.tooltips[id][2].bindHide).off();
};
this.open = function(e, id) {
if(this.tooltips[id][3])
{
return;
}
$.stop(e);
var mousePosition = $.mousePosition(e);
this.tooltips[id][3] = true;
setTimeout($.bind(function() {
if(this.tooltips[id][3])
{
//force to close
this.__parent.close.call(this, false);
//set the position
switch(this.tooltips[id][2].position)
{
case 'top':
this.openTop(id);
break;
case 'left':
this.openLeft(id);
break;
case 'bottom':
this.openBottom(id);
break;
case 'right':
this.openRight(id);
break;
default:
this.openMouse(mousePosition, id);
break;
}
}
if(this.options.autohide)
{
setTimeout($.bind(function() {
this.close(e, id);
}, this), this.options.autohide);
}
//call parent open
if(this.trigger('open', this) === false)
{
return false;
}
}, this, e), this.options.showDelay || 0);
};
this.openTop = function(id) {
//set the body
this.setBody(this.tooltips[id][1].clone());
//call parent open no triggers
this.__parent.open.call(this, false);
var triggerCoords = this.tooltips[id][0].trueCoordinates(), //get the coords of the trigger
targetCoords = this.target.trueCoordinates(), //get the coords of the box
offset = {//find the difference between the top trigger and the bottom target
top: targetCoords[1].top-triggerCoords[0].top,
left: targetCoords[0].left-triggerCoords[0].left},
margin = {//adjust the margintop on the target to the offset found
top: (parseInt(this.target.css('marginTop')) || 0) - offset.top + this.tooltips[id][2].offsetTop,
left: (parseInt(this.target.css('marginLeft')) || 0) - offset.left + this.tooltips[id][2].offsetLeft};
//set the css
this.target.css({
marginTop: margin.top+'px',
marginLeft: margin.left+'px',
zIndex: this.tooltips[id][2].zIndex || 'auto'
});
return this;
};
this.openLeft = function(id) {
//set the body
this.setBody(this.tooltips[id][1].clone());
//call parent open no triggers
this.__parent.open.call(this, false);
var triggerCoords = this.tooltips[id][0].trueCoordinates(), //get the coords of the trigger
targetCoords = this.target.trueCoordinates(), //get the coords of the box
offset = {//find the difference between the top trigger and the bottom target
top: targetCoords[0].top-triggerCoords[0].top,
left: targetCoords[1].left-triggerCoords[0].left},
margin = {//adjust the margintop on the target to the offset found
top: (parseInt(this.target.css('marginTop')) || 0) - offset.top + this.tooltips[id][2].offsetTop,
left: (parseInt(this.target.css('marginLeft')) || 0) - offset.left + this.tooltips[id][2].offsetLeft};
//set the css
this.target.css({
marginTop: margin.top+'px',
marginLeft: margin.left+'px',
zIndex: this.tooltips[id][2].zIndex || 'auto'
});
return this;
};
this.openBottom = function(id) {
//set the body
this.setBody(this.tooltips[id][1].clone());
//call parent open no triggers
this.__parent.open.call(this, false);
var triggerCoords = this.tooltips[id][0].trueCoordinates(), //get the coords of the trigger
targetCoords = this.target.trueCoordinates(), //get the coords of the box
offset = {//find the difference between the top trigger and the bottom target
top: targetCoords[0].top-triggerCoords[1].top,
left: targetCoords[0].left-triggerCoords[0].left},
margin = {//adjust the margintop on the target to the offset found
top: (parseInt(this.target.css('marginTop')) || 0) - offset.top + this.tooltips[id][2].offsetTop,
left: (parseInt(this.target.css('marginLeft')) || 0) - offset.left + this.tooltips[id][2].offsetLeft};
//set the css
this.target.css({
marginTop: margin.top+'px',
marginLeft: margin.left+'px',
zIndex: this.tooltips[id][2].zIndex || 'auto'
});
return this;
};
this.openRight = function(id) {
//set the body
this.setBody(this.tooltips[id][1].clone());
//call parent open no triggers
this.__parent.open.call(this, false);
var triggerCoords = this.tooltips[id][0].trueCoordinates(), //get the coords of the trigger
targetCoords = this.target.trueCoordinates(), //get the coords of the box
offset = {//find the difference between the top trigger and the bottom target
top: targetCoords[0].top-triggerCoords[0].top,
left: targetCoords[0].left-triggerCoords[1].left},
margin = {//adjust the margintop on the target to the offset found
top: (parseInt(this.target.css('marginTop')) || 0) - offset.top + this.tooltips[id][2].offsetTop,
left: (parseInt(this.target.css('marginLeft')) || 0) - offset.left + this.tooltips[id][2].offsetLeft};
//set the css
this.target.css({
marginTop: margin.top+'px',
marginLeft: margin.left+'px',
zIndex: this.tooltips[id][2].zIndex || 'auto'
});
return this;
};
this.openMouse = function(mousePosition, id) {
//set the body
this.setBody(this.tooltips[id][1].clone());
//call parent open no triggers
this.__parent.open.call(this, false);
var offset = {}, margin,
targetCoords = this.target.trueCoordinates(), //get the coords of the box
windowSize = $.windowSize(), //get the size of the window
targetSize = this.target.trueSize(); //get the size of the box
switch(true)
{
case mousePosition.left+targetSize.width < windowSize.width:
offset.left = targetCoords[0].left-mousePosition.left;
break;
default:
offset.left = targetCoords[1].left-mousePosition.left-3;
break;
}
switch(true)
{
case mousePosition.top+targetSize.height < windowSize.height:
offset.top = targetCoords[0].top-mousePosition.top;
break;
default:
offset.top = targetCoords[1].top-mousePosition.top-3;
break;
}
margin = {//adjust the margintop on the target to the offset found
top: (parseInt(this.target.css('marginTop')) || 0) - offset.top + this.tooltips[id][2].offsetTop,
left: (parseInt(this.target.css('marginLeft')) || 0) - offset.left + this.tooltips[id][2].offsetLeft};
//set the css
this.target.css({
marginTop: margin.top+'px',
marginLeft: margin.left+'px',
zIndex: this.tooltips[id][2].zIndex || 'auto'
});
return this;
};
this.close = function(e, id) {
if(!this.tooltips[id][3])
{
return;
}
$.stop(e);
var targetCoords = this.target.trueCoordinates(), //get the coords of the box
mousePosition = $.mousePosition(e); //get the mouse position
if(!(targetCoords[0].left < mousePosition.left &&
mousePosition.left < targetCoords[1].left &&
targetCoords[0].top < mousePosition.top &&
mousePosition.top < targetCoords[1].top))
{
this.tooltips[id][3] = false;
setTimeout($.bind(function() {
if(!this.tooltips[id][3])
{
//call parent close
if(this.__parent.close.call(this) === false)
{
return false;
}
}
}, this), this.options.hideDelay || 0);
}
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
if(this.options.modal)
{
this.events.modal.click.off()
}
this.events.window.resize.off()
this.__parent.__destruct.call(this);
};
}, $.Box.prototype);
/* Field - Slider Class
--------------------------------*/
$.def('Slider', new function() {
this.CLASSNAME = 'Slider';
this.HORIZONTAL = 'horizontal';
this.VERTICAL = 'vertical';
this.LEFT = 'left';
this.TOP = 'top';
/* Constructor
-------------------------------------*/
this.__construct = function (options) {
this.options = $.combine({
values: [0,100],
range: true,
floating: false,
direction: this.HORIZONTAL
}, options || {});
this.options.hValues = $.type(this.options.hValues, 'array') ? this.options.hValues : this.options.values;
this.options.vValues = $.type(this.options.vValues, 'array') ? this.options.vValues : this.options.values;
this.options.hRange = $.type(this.options.hRange, 'boolean') ? this.options.hRange : this.options.range;
this.options.vRange = $.type(this.options.vRange, 'boolean') ? this.options.vRange : this.options.range;
this.handle = $.toElement('<div class="handle"></div>', 0);
this.field = $.toElement('<div class="slider"></div>', 0).append(this.handle);
//make handle draggable
this.drag = $.Draggable(this.handle, {
container: this.field,
direction: this.options.direction
});
this.drag.on('start', $.bind(this.eventStart, this));
this.drag.on('drag', $.bind(this.eventSlide, this));
this.drag.on('stop', $.bind(this.eventStop, this));
this.field.on('mousedown', $.bind(this.eventMousedown, this));
};
/* Public Methods
-------------------------------------*/
this.getPosition = function(percent, direction) {
direction = direction == this.HORIZONTAL ? this.HORIZONTAL : this.VERTICAL;
var property = direction == this.HORIZONTAL ? this.LEFT: this.TOP;
//this is some tricky math
//find out what percentage from the start of the container to the middle of the handle is
//first get the coords of the handle
var handleCoords = this.handle.trueCoordinates(),
//radius = the size of the handle / 2
radius = (handleCoords[1][property] - handleCoords[0][property]) / 2;
//get the coords of the container
containerCoords = this.field.trueCoordinates();
//and trim the coords - the radius
containerCoords[0][property] += radius;
containerCoords[1][property] -= radius;
//now get the size of the new container cooords
containerSize = containerCoords[1][property] - containerCoords[0][property];
return containerSize * percent * .01;
};
this.getPercent = function(position, size, direction) {
direction = direction == this.HORIZONTAL ? this.HORIZONTAL : this.VERTICAL;
var percent, property = direction == this.HORIZONTAL ? this.LEFT: this.TOP;
//this is some tricky math
//radius = the size of the handle / 2
radius = size / 2;
//get the coords of the container
containerCoords = this.field.trueCoordinates();
//and trim the coords - the radius
containerCoords[0][property] += radius;
containerCoords[1][property] -= radius;
//take the radius and add that to the first coordinate
var tick = radius + position;
//now get the size of the new container cooords
containerSize = containerCoords[1][property] - containerCoords[0][property],
//get the size of the tick
tickSize = tick - containerCoords[0][property];
//lastly calculate the percentages tickSize / containerSize
percent = tickSize / containerSize;
if(percent < 0)
{
percent = 0;
}
if(percent > 1)
{
percent = 1;
}
return percent;
};
this.getValue = function(percent, direction) {
direction = direction == this.HORIZONTAL ? this.HORIZONTAL : this.VERTICAL;
var value = null,
values = direction == this.HORIZONTAL ? this.options.hValues : this.options.vValues,
range = direction == this.HORIZONTAL ? this.options.hRange : this.options.vRange,
property = direction == this.HORIZONTAL ? this.LEFT: this.TOP,
property2 = direction == this.HORIZONTAL ? 'width': 'height',
coords = this.handle.trueCoordinates(),
position = coords[0],
size = this.handle.trueSize();
percent = percent || this.getPercent(position[property], size[property2], direction);
if(values.length == 2 && $.type(values[0], 'number') &&
$.type(values[1], 'number') && range)
{
//take the difference between the min and max
range = values[1] - values[0];
value = (percent * range) + values[0];
if(!this.options.floating)
{
value = Math.round(value);
}
}
else
{
//build some ticks
$.parse(values, $.bind(function(tick, val) {
//if the percent is > tick / value.length
if(percent <= ((tick+1) / values.length))
{
value = val;
return false;
}
}, this));
}
return value;
};
this.setValue = function(value, direction) {
direction = direction == this.HORIZONTAL ? this.HORIZONTAL : this.VERTICAL;
this.handle.css('position', 'relative');
//trigger
if(this.trigger('change', this, value, direction) === false)
{
return false
}
var percent, position,
values = direction == this.HORIZONTAL ? this.options.hValues : this.options.vValues,
property = direction == this.HORIZONTAL ? this.LEFT: this.TOP,
range = direction == this.HORIZONTAL ? this.options.hRange : this.options.vRange;
if(values.length > 2 || !range)
{
//find value
$.parse(values, $.bind(function(tick, val) {
if(val == value)
{
percent = (tick + .5) / values.length * 100;
position = this.getPosition(percent, direction);
this.handle.css(property, position+'px');
return false;
}
}, this));
}
else
{
//some math here
var diff = value - values[0];
range = values[1] - values[0];
diff = diff < 0 ? 0 : diff;
percent = diff / range * 100;
position = this.getPosition(percent, direction);
this.handle.css(property, position+'px');
}
return this;
};
this.eventMousedown = function(e) {
if(this.dragging)
{
this.dragging = false;
return true;
}
//get the mouse position
var mousePosition = $.mousePosition(e),
//get the size of the handle
size = this.handle.trueSize(),
//center the handle on the mouse click
position = {
left: mousePosition.left - (size.width / 2),
top: mousePosition.top - (size.height / 2),
},
directions = [this.HORIZONTAL, this.VERTICAL],
triggerValues = [];
if($.has([this.HORIZONTAL, this.VERTICAL], this.options.direction))
{
directions = [this.options.direction];
}
$.parse(directions, $.bind(function(k, direction) {
var property = direction == this.HORIZONTAL ? this.LEFT: this.TOP,
property2 = direction == this.HORIZONTAL ? 'width': 'height',
percent = this.getPercent(position[property], size[property2], direction),
values = direction == this.HORIZONTAL ? this.options.hValues : this.options.vValues,
range = direction == this.HORIZONTAL ? this.options.hRange : this.options.vRange,
value = this.getValue(percent, direction);
triggerValues.push(value);
if($.type(value, 'undefined'))
{
return true;
}
if(values.length > 2 || !range)
{
this.setValue(value, direction);
}
else
{
//set the raw value
this.handle.css(property, this.getPosition(percent * 100, direction) + 'px');
}
}, this));
var value;
switch(this.options.direction)
{
case this.VERTICAL:
value = triggerValues[0];
break;
case this.HORIZONTAL:
value = triggerValues[0];
break;
default:
value = {horizontal: triggerValues[0], vertical: triggerValues[1]};
break;
}
this.drag.start(e);
};
this.eventStart = function() {
this.dragging = true;
};
this.eventSlide = function(dragObj, e, relative, position) {
var size = this.handle.trueSize(),
triggerValues = [],
directions = [this.HORIZONTAL, this.VERTICAL];
if($.has([this.HORIZONTAL, this.VERTICAL], this.options.direction))
{
directions = [this.options.direction];
}
$.parse(directions, $.bind(function(k, direction) {
var property = direction == this.HORIZONTAL ? this.LEFT: this.TOP,
property2 = direction == this.HORIZONTAL ? 'width': 'height',
percent = this.getPercent(position[property], size[property2], direction),
value = this.getValue(percent, direction),
values = direction == this.HORIZONTAL ? this.options.hValues : this.options.vValues,
range = direction == this.HORIZONTAL ? this.options.hRange : this.options.vRange;
triggerValues.push(value);
if($.type(value) == 'undefined')
{
return false;
}
if(values.length > 2 || !range)
{
$.parse(values, $.bind(function(tick, val) {
if(val == value)
{
var percent = ((tick + .5) / values.length) * 100;
relative[property] = this.getPosition(percent, direction);
return false;
}
}, this));
}
}, this));
var value;
switch(this.options.direction)
{
case this.VERTICAL:
value = triggerValues[0];
break;
case this.HORIZONTAL:
value = triggerValues[0];
break;
default:
value = {horizontal: triggerValues[0], vertical: triggerValues[1]};
break;
}
return this.trigger('slide', this, value);
};
this.eventStop = function() {
return this.trigger('change', this, this.getValue());
};
/* Destructor
-------------------------------------*/
this.__destruct = function() {
$.destroy(this);
};
}, $.Base);
return $;
})({path: 'http://eve.openovate.com/themes/admin/scripts/'});