diff --git a/Demo/index.html b/Demo/index.html
index 260a768..918ed19 100644
--- a/Demo/index.html
+++ b/Demo/index.html
@@ -12,10 +12,7 @@
-
-
-
-
+
@@ -30,7 +27,7 @@
t.add('Tag 1').add('Tag 2').add('Tag 3');
// With custom adding keys
- var t2 = new TextboxList('form_tags_input_2', {bitsOptions:{editable:{addKeys: 188}}});
+ var t2 = new TextboxList('form_tags_input_2', {bitsOptions:{editable:{addKeys: [188, 32]},stopEnter:true}});
t2.add('Tag 1').add('Tag 2');
// Autocomplete initialization
@@ -69,7 +66,7 @@
/* Preloader for autocomplete */
.textboxlist-loading { background: url('images/spinner.gif') no-repeat 380px center; }
-
+
/* Autocomplete results styling */
.form_friends .textboxlist-autocomplete-result { overflow: hidden; zoom: 1; }
.form_friends .textboxlist-autocomplete-result img { float: left; padding-right: 10px; }
diff --git a/Demo/mootools-core-1.4.5-full-nocompat.js b/Demo/mootools-core-1.4.5-full-nocompat.js
new file mode 100644
index 0000000..d4dc9b9
--- /dev/null
+++ b/Demo/mootools-core-1.4.5-full-nocompat.js
@@ -0,0 +1,5976 @@
+/*
+---
+MooTools: the javascript framework
+
+web build:
+ - http://mootools.net/core/76bf47062d6c1983d66ce47ad66aa0e0
+
+packager build:
+ - packager build Core/Core Core/Array Core/String Core/Number Core/Function Core/Object Core/Event Core/Browser Core/Class Core/Class.Extras Core/Slick.Parser Core/Slick.Finder Core/Element Core/Element.Style Core/Element.Event Core/Element.Delegation Core/Element.Dimensions Core/Fx Core/Fx.CSS Core/Fx.Tween Core/Fx.Morph Core/Fx.Transitions Core/Request Core/Request.HTML Core/Request.JSON Core/Cookie Core/JSON Core/DOMReady Core/Swiff
+
+...
+*/
+
+/*
+---
+
+name: Core
+
+description: The heart of MooTools.
+
+license: MIT-style license.
+
+copyright: Copyright (c) 2006-2012 [Valerio Proietti](http://mad4milk.net/).
+
+authors: The MooTools production team (http://mootools.net/developers/)
+
+inspiration:
+ - Class implementation inspired by [Base.js](http://dean.edwards.name/weblog/2006/03/base/) Copyright (c) 2006 Dean Edwards, [GNU Lesser General Public License](http://opensource.org/licenses/lgpl-license.php)
+ - Some functionality inspired by [Prototype.js](http://prototypejs.org) Copyright (c) 2005-2007 Sam Stephenson, [MIT License](http://opensource.org/licenses/mit-license.php)
+
+provides: [Core, MooTools, Type, typeOf, instanceOf, Native]
+
+...
+*/
+
+(function(){
+
+this.MooTools = {
+ version: '1.4.5',
+ build: '74e34796f5f76640cdb98853004650aea1499d69'
+};
+
+// typeOf, instanceOf
+
+var typeOf = this.typeOf = function(item){
+ if (item == null) return 'null';
+ if (item.$family != null) return item.$family();
+
+ if (item.nodeName){
+ if (item.nodeType == 1) return 'element';
+ if (item.nodeType == 3) return (/\S/).test(item.nodeValue) ? 'textnode' : 'whitespace';
+ } else if (typeof item.length == 'number'){
+ if (item.callee) return 'arguments';
+ if ('item' in item) return 'collection';
+ }
+
+ return typeof item;
+};
+
+var instanceOf = this.instanceOf = function(item, object){
+ if (item == null) return false;
+ var constructor = item.$constructor || item.constructor;
+ while (constructor){
+ if (constructor === object) return true;
+ constructor = constructor.parent;
+ }
+ /**/
+ if (!item.hasOwnProperty) return false;
+ /**/
+ return item instanceof object;
+};
+
+// Function overloading
+
+var Function = this.Function;
+
+var enumerables = true;
+for (var i in {toString: 1}) enumerables = null;
+if (enumerables) enumerables = ['hasOwnProperty', 'valueOf', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'constructor'];
+
+Function.prototype.overloadSetter = function(usePlural){
+ var self = this;
+ return function(a, b){
+ if (a == null) return this;
+ if (usePlural || typeof a != 'string'){
+ for (var k in a) self.call(this, k, a[k]);
+ if (enumerables) for (var i = enumerables.length; i--;){
+ k = enumerables[i];
+ if (a.hasOwnProperty(k)) self.call(this, k, a[k]);
+ }
+ } else {
+ self.call(this, a, b);
+ }
+ return this;
+ };
+};
+
+Function.prototype.overloadGetter = function(usePlural){
+ var self = this;
+ return function(a){
+ var args, result;
+ if (typeof a != 'string') args = a;
+ else if (arguments.length > 1) args = arguments;
+ else if (usePlural) args = [a];
+ if (args){
+ result = {};
+ for (var i = 0; i < args.length; i++) result[args[i]] = self.call(this, args[i]);
+ } else {
+ result = self.call(this, a);
+ }
+ return result;
+ };
+};
+
+Function.prototype.extend = function(key, value){
+ this[key] = value;
+}.overloadSetter();
+
+Function.prototype.implement = function(key, value){
+ this.prototype[key] = value;
+}.overloadSetter();
+
+// From
+
+var slice = Array.prototype.slice;
+
+Function.from = function(item){
+ return (typeOf(item) == 'function') ? item : function(){
+ return item;
+ };
+};
+
+Array.from = function(item){
+ if (item == null) return [];
+ return (Type.isEnumerable(item) && typeof item != 'string') ? (typeOf(item) == 'array') ? item : slice.call(item) : [item];
+};
+
+Number.from = function(item){
+ var number = parseFloat(item);
+ return isFinite(number) ? number : null;
+};
+
+String.from = function(item){
+ return item + '';
+};
+
+// hide, protect
+
+Function.implement({
+
+ hide: function(){
+ this.$hidden = true;
+ return this;
+ },
+
+ protect: function(){
+ this.$protected = true;
+ return this;
+ }
+
+});
+
+// Type
+
+var Type = this.Type = function(name, object){
+ if (name){
+ var lower = name.toLowerCase();
+ var typeCheck = function(item){
+ return (typeOf(item) == lower);
+ };
+
+ Type['is' + name] = typeCheck;
+ if (object != null){
+ object.prototype.$family = (function(){
+ return lower;
+ }).hide();
+
+ }
+ }
+
+ if (object == null) return null;
+
+ object.extend(this);
+ object.$constructor = Type;
+ object.prototype.$constructor = object;
+
+ return object;
+};
+
+var toString = Object.prototype.toString;
+
+Type.isEnumerable = function(item){
+ return (item != null && typeof item.length == 'number' && toString.call(item) != '[object Function]' );
+};
+
+var hooks = {};
+
+var hooksOf = function(object){
+ var type = typeOf(object.prototype);
+ return hooks[type] || (hooks[type] = []);
+};
+
+var implement = function(name, method){
+ if (method && method.$hidden) return;
+
+ var hooks = hooksOf(this);
+
+ for (var i = 0; i < hooks.length; i++){
+ var hook = hooks[i];
+ if (typeOf(hook) == 'type') implement.call(hook, name, method);
+ else hook.call(this, name, method);
+ }
+
+ var previous = this.prototype[name];
+ if (previous == null || !previous.$protected) this.prototype[name] = method;
+
+ if (this[name] == null && typeOf(method) == 'function') extend.call(this, name, function(item){
+ return method.apply(item, slice.call(arguments, 1));
+ });
+};
+
+var extend = function(name, method){
+ if (method && method.$hidden) return;
+ var previous = this[name];
+ if (previous == null || !previous.$protected) this[name] = method;
+};
+
+Type.implement({
+
+ implement: implement.overloadSetter(),
+
+ extend: extend.overloadSetter(),
+
+ alias: function(name, existing){
+ implement.call(this, name, this.prototype[existing]);
+ }.overloadSetter(),
+
+ mirror: function(hook){
+ hooksOf(this).push(hook);
+ return this;
+ }
+
+});
+
+new Type('Type', Type);
+
+// Default Types
+
+var force = function(name, object, methods){
+ var isType = (object != Object),
+ prototype = object.prototype;
+
+ if (isType) object = new Type(name, object);
+
+ for (var i = 0, l = methods.length; i < l; i++){
+ var key = methods[i],
+ generic = object[key],
+ proto = prototype[key];
+
+ if (generic) generic.protect();
+ if (isType && proto) object.implement(key, proto.protect());
+ }
+
+ if (isType){
+ var methodsEnumerable = prototype.propertyIsEnumerable(methods[0]);
+ object.forEachMethod = function(fn){
+ if (!methodsEnumerable) for (var i = 0, l = methods.length; i < l; i++){
+ fn.call(prototype, prototype[methods[i]], methods[i]);
+ }
+ for (var key in prototype) fn.call(prototype, prototype[key], key)
+ };
+ }
+
+ return force;
+};
+
+force('String', String, [
+ 'charAt', 'charCodeAt', 'concat', 'indexOf', 'lastIndexOf', 'match', 'quote', 'replace', 'search',
+ 'slice', 'split', 'substr', 'substring', 'trim', 'toLowerCase', 'toUpperCase'
+])('Array', Array, [
+ 'pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift', 'concat', 'join', 'slice',
+ 'indexOf', 'lastIndexOf', 'filter', 'forEach', 'every', 'map', 'some', 'reduce', 'reduceRight'
+])('Number', Number, [
+ 'toExponential', 'toFixed', 'toLocaleString', 'toPrecision'
+])('Function', Function, [
+ 'apply', 'call', 'bind'
+])('RegExp', RegExp, [
+ 'exec', 'test'
+])('Object', Object, [
+ 'create', 'defineProperty', 'defineProperties', 'keys',
+ 'getPrototypeOf', 'getOwnPropertyDescriptor', 'getOwnPropertyNames',
+ 'preventExtensions', 'isExtensible', 'seal', 'isSealed', 'freeze', 'isFrozen'
+])('Date', Date, ['now']);
+
+Object.extend = extend.overloadSetter();
+
+Date.extend('now', function(){
+ return +(new Date);
+});
+
+new Type('Boolean', Boolean);
+
+// fixes NaN returning as Number
+
+Number.prototype.$family = function(){
+ return isFinite(this) ? 'number' : 'null';
+}.hide();
+
+// Number.random
+
+Number.extend('random', function(min, max){
+ return Math.floor(Math.random() * (max - min + 1) + min);
+});
+
+// forEach, each
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+Object.extend('forEach', function(object, fn, bind){
+ for (var key in object){
+ if (hasOwnProperty.call(object, key)) fn.call(bind, object[key], key, object);
+ }
+});
+
+Object.each = Object.forEach;
+
+Array.implement({
+
+ forEach: function(fn, bind){
+ for (var i = 0, l = this.length; i < l; i++){
+ if (i in this) fn.call(bind, this[i], i, this);
+ }
+ },
+
+ each: function(fn, bind){
+ Array.forEach(this, fn, bind);
+ return this;
+ }
+
+});
+
+// Array & Object cloning, Object merging and appending
+
+var cloneOf = function(item){
+ switch (typeOf(item)){
+ case 'array': return item.clone();
+ case 'object': return Object.clone(item);
+ default: return item;
+ }
+};
+
+Array.implement('clone', function(){
+ var i = this.length, clone = new Array(i);
+ while (i--) clone[i] = cloneOf(this[i]);
+ return clone;
+});
+
+var mergeOne = function(source, key, current){
+ switch (typeOf(current)){
+ case 'object':
+ if (typeOf(source[key]) == 'object') Object.merge(source[key], current);
+ else source[key] = Object.clone(current);
+ break;
+ case 'array': source[key] = current.clone(); break;
+ default: source[key] = current;
+ }
+ return source;
+};
+
+Object.extend({
+
+ merge: function(source, k, v){
+ if (typeOf(k) == 'string') return mergeOne(source, k, v);
+ for (var i = 1, l = arguments.length; i < l; i++){
+ var object = arguments[i];
+ for (var key in object) mergeOne(source, key, object[key]);
+ }
+ return source;
+ },
+
+ clone: function(object){
+ var clone = {};
+ for (var key in object) clone[key] = cloneOf(object[key]);
+ return clone;
+ },
+
+ append: function(original){
+ for (var i = 1, l = arguments.length; i < l; i++){
+ var extended = arguments[i] || {};
+ for (var key in extended) original[key] = extended[key];
+ }
+ return original;
+ }
+
+});
+
+// Object-less types
+
+['Object', 'WhiteSpace', 'TextNode', 'Collection', 'Arguments'].each(function(name){
+ new Type(name);
+});
+
+// Unique ID
+
+var UID = Date.now();
+
+String.extend('uniqueID', function(){
+ return (UID++).toString(36);
+});
+
+
+
+})();
+
+
+/*
+---
+
+name: Array
+
+description: Contains Array Prototypes like each, contains, and erase.
+
+license: MIT-style license.
+
+requires: Type
+
+provides: Array
+
+...
+*/
+
+Array.implement({
+
+ /**/
+ every: function(fn, bind){
+ for (var i = 0, l = this.length >>> 0; i < l; i++){
+ if ((i in this) && !fn.call(bind, this[i], i, this)) return false;
+ }
+ return true;
+ },
+
+ filter: function(fn, bind){
+ var results = [];
+ for (var value, i = 0, l = this.length >>> 0; i < l; i++) if (i in this){
+ value = this[i];
+ if (fn.call(bind, value, i, this)) results.push(value);
+ }
+ return results;
+ },
+
+ indexOf: function(item, from){
+ var length = this.length >>> 0;
+ for (var i = (from < 0) ? Math.max(0, length + from) : from || 0; i < length; i++){
+ if (this[i] === item) return i;
+ }
+ return -1;
+ },
+
+ map: function(fn, bind){
+ var length = this.length >>> 0, results = Array(length);
+ for (var i = 0; i < length; i++){
+ if (i in this) results[i] = fn.call(bind, this[i], i, this);
+ }
+ return results;
+ },
+
+ some: function(fn, bind){
+ for (var i = 0, l = this.length >>> 0; i < l; i++){
+ if ((i in this) && fn.call(bind, this[i], i, this)) return true;
+ }
+ return false;
+ },
+ /*!ES5>*/
+
+ clean: function(){
+ return this.filter(function(item){
+ return item != null;
+ });
+ },
+
+ invoke: function(methodName){
+ var args = Array.slice(arguments, 1);
+ return this.map(function(item){
+ return item[methodName].apply(item, args);
+ });
+ },
+
+ associate: function(keys){
+ var obj = {}, length = Math.min(this.length, keys.length);
+ for (var i = 0; i < length; i++) obj[keys[i]] = this[i];
+ return obj;
+ },
+
+ link: function(object){
+ var result = {};
+ for (var i = 0, l = this.length; i < l; i++){
+ for (var key in object){
+ if (object[key](this[i])){
+ result[key] = this[i];
+ delete object[key];
+ break;
+ }
+ }
+ }
+ return result;
+ },
+
+ contains: function(item, from){
+ return this.indexOf(item, from) != -1;
+ },
+
+ append: function(array){
+ this.push.apply(this, array);
+ return this;
+ },
+
+ getLast: function(){
+ return (this.length) ? this[this.length - 1] : null;
+ },
+
+ getRandom: function(){
+ return (this.length) ? this[Number.random(0, this.length - 1)] : null;
+ },
+
+ include: function(item){
+ if (!this.contains(item)) this.push(item);
+ return this;
+ },
+
+ combine: function(array){
+ for (var i = 0, l = array.length; i < l; i++) this.include(array[i]);
+ return this;
+ },
+
+ erase: function(item){
+ for (var i = this.length; i--;){
+ if (this[i] === item) this.splice(i, 1);
+ }
+ return this;
+ },
+
+ empty: function(){
+ this.length = 0;
+ return this;
+ },
+
+ flatten: function(){
+ var array = [];
+ for (var i = 0, l = this.length; i < l; i++){
+ var type = typeOf(this[i]);
+ if (type == 'null') continue;
+ array = array.concat((type == 'array' || type == 'collection' || type == 'arguments' || instanceOf(this[i], Array)) ? Array.flatten(this[i]) : this[i]);
+ }
+ return array;
+ },
+
+ pick: function(){
+ for (var i = 0, l = this.length; i < l; i++){
+ if (this[i] != null) return this[i];
+ }
+ return null;
+ },
+
+ hexToRgb: function(array){
+ if (this.length != 3) return null;
+ var rgb = this.map(function(value){
+ if (value.length == 1) value += value;
+ return value.toInt(16);
+ });
+ return (array) ? rgb : 'rgb(' + rgb + ')';
+ },
+
+ rgbToHex: function(array){
+ if (this.length < 3) return null;
+ if (this.length == 4 && this[3] == 0 && !array) return 'transparent';
+ var hex = [];
+ for (var i = 0; i < 3; i++){
+ var bit = (this[i] - 0).toString(16);
+ hex.push((bit.length == 1) ? '0' + bit : bit);
+ }
+ return (array) ? hex : '#' + hex.join('');
+ }
+
+});
+
+
+
+
+/*
+---
+
+name: String
+
+description: Contains String Prototypes like camelCase, capitalize, test, and toInt.
+
+license: MIT-style license.
+
+requires: Type
+
+provides: String
+
+...
+*/
+
+String.implement({
+
+ test: function(regex, params){
+ return ((typeOf(regex) == 'regexp') ? regex : new RegExp('' + regex, params)).test(this);
+ },
+
+ contains: function(string, separator){
+ return (separator) ? (separator + this + separator).indexOf(separator + string + separator) > -1 : String(this).indexOf(string) > -1;
+ },
+
+ trim: function(){
+ return String(this).replace(/^\s+|\s+$/g, '');
+ },
+
+ clean: function(){
+ return String(this).replace(/\s+/g, ' ').trim();
+ },
+
+ camelCase: function(){
+ return String(this).replace(/-\D/g, function(match){
+ return match.charAt(1).toUpperCase();
+ });
+ },
+
+ hyphenate: function(){
+ return String(this).replace(/[A-Z]/g, function(match){
+ return ('-' + match.charAt(0).toLowerCase());
+ });
+ },
+
+ capitalize: function(){
+ return String(this).replace(/\b[a-z]/g, function(match){
+ return match.toUpperCase();
+ });
+ },
+
+ escapeRegExp: function(){
+ return String(this).replace(/([-.*+?^${}()|[\]\/\\])/g, '\\$1');
+ },
+
+ toInt: function(base){
+ return parseInt(this, base || 10);
+ },
+
+ toFloat: function(){
+ return parseFloat(this);
+ },
+
+ hexToRgb: function(array){
+ var hex = String(this).match(/^#?(\w{1,2})(\w{1,2})(\w{1,2})$/);
+ return (hex) ? hex.slice(1).hexToRgb(array) : null;
+ },
+
+ rgbToHex: function(array){
+ var rgb = String(this).match(/\d{1,3}/g);
+ return (rgb) ? rgb.rgbToHex(array) : null;
+ },
+
+ substitute: function(object, regexp){
+ return String(this).replace(regexp || (/\\?\{([^{}]+)\}/g), function(match, name){
+ if (match.charAt(0) == '\\') return match.slice(1);
+ return (object[name] != null) ? object[name] : '';
+ });
+ }
+
+});
+
+
+/*
+---
+
+name: Number
+
+description: Contains Number Prototypes like limit, round, times, and ceil.
+
+license: MIT-style license.
+
+requires: Type
+
+provides: Number
+
+...
+*/
+
+Number.implement({
+
+ limit: function(min, max){
+ return Math.min(max, Math.max(min, this));
+ },
+
+ round: function(precision){
+ precision = Math.pow(10, precision || 0).toFixed(precision < 0 ? -precision : 0);
+ return Math.round(this * precision) / precision;
+ },
+
+ times: function(fn, bind){
+ for (var i = 0; i < this; i++) fn.call(bind, i, this);
+ },
+
+ toFloat: function(){
+ return parseFloat(this);
+ },
+
+ toInt: function(base){
+ return parseInt(this, base || 10);
+ }
+
+});
+
+Number.alias('each', 'times');
+
+(function(math){
+ var methods = {};
+ math.each(function(name){
+ if (!Number[name]) methods[name] = function(){
+ return Math[name].apply(null, [this].concat(Array.from(arguments)));
+ };
+ });
+ Number.implement(methods);
+})(['abs', 'acos', 'asin', 'atan', 'atan2', 'ceil', 'cos', 'exp', 'floor', 'log', 'max', 'min', 'pow', 'sin', 'sqrt', 'tan']);
+
+
+/*
+---
+
+name: Function
+
+description: Contains Function Prototypes like create, bind, pass, and delay.
+
+license: MIT-style license.
+
+requires: Type
+
+provides: Function
+
+...
+*/
+
+Function.extend({
+
+ attempt: function(){
+ for (var i = 0, l = arguments.length; i < l; i++){
+ try {
+ return arguments[i]();
+ } catch (e){}
+ }
+ return null;
+ }
+
+});
+
+Function.implement({
+
+ attempt: function(args, bind){
+ try {
+ return this.apply(bind, Array.from(args));
+ } catch (e){}
+
+ return null;
+ },
+
+ /**/
+ bind: function(that){
+ var self = this,
+ args = arguments.length > 1 ? Array.slice(arguments, 1) : null,
+ F = function(){};
+
+ var bound = function(){
+ var context = that, length = arguments.length;
+ if (this instanceof bound){
+ F.prototype = self.prototype;
+ context = new F;
+ }
+ var result = (!args && !length)
+ ? self.call(context)
+ : self.apply(context, args && length ? args.concat(Array.slice(arguments)) : args || arguments);
+ return context == that ? result : context;
+ };
+ return bound;
+ },
+ /*!ES5-bind>*/
+
+ pass: function(args, bind){
+ var self = this;
+ if (args != null) args = Array.from(args);
+ return function(){
+ return self.apply(bind, args || arguments);
+ };
+ },
+
+ delay: function(delay, bind, args){
+ return setTimeout(this.pass((args == null ? [] : args), bind), delay);
+ },
+
+ periodical: function(periodical, bind, args){
+ return setInterval(this.pass((args == null ? [] : args), bind), periodical);
+ }
+
+});
+
+
+
+
+/*
+---
+
+name: Object
+
+description: Object generic methods
+
+license: MIT-style license.
+
+requires: Type
+
+provides: [Object, Hash]
+
+...
+*/
+
+(function(){
+
+var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+Object.extend({
+
+ subset: function(object, keys){
+ var results = {};
+ for (var i = 0, l = keys.length; i < l; i++){
+ var k = keys[i];
+ if (k in object) results[k] = object[k];
+ }
+ return results;
+ },
+
+ map: function(object, fn, bind){
+ var results = {};
+ for (var key in object){
+ if (hasOwnProperty.call(object, key)) results[key] = fn.call(bind, object[key], key, object);
+ }
+ return results;
+ },
+
+ filter: function(object, fn, bind){
+ var results = {};
+ for (var key in object){
+ var value = object[key];
+ if (hasOwnProperty.call(object, key) && fn.call(bind, value, key, object)) results[key] = value;
+ }
+ return results;
+ },
+
+ every: function(object, fn, bind){
+ for (var key in object){
+ if (hasOwnProperty.call(object, key) && !fn.call(bind, object[key], key)) return false;
+ }
+ return true;
+ },
+
+ some: function(object, fn, bind){
+ for (var key in object){
+ if (hasOwnProperty.call(object, key) && fn.call(bind, object[key], key)) return true;
+ }
+ return false;
+ },
+
+ keys: function(object){
+ var keys = [];
+ for (var key in object){
+ if (hasOwnProperty.call(object, key)) keys.push(key);
+ }
+ return keys;
+ },
+
+ values: function(object){
+ var values = [];
+ for (var key in object){
+ if (hasOwnProperty.call(object, key)) values.push(object[key]);
+ }
+ return values;
+ },
+
+ getLength: function(object){
+ return Object.keys(object).length;
+ },
+
+ keyOf: function(object, value){
+ for (var key in object){
+ if (hasOwnProperty.call(object, key) && object[key] === value) return key;
+ }
+ return null;
+ },
+
+ contains: function(object, value){
+ return Object.keyOf(object, value) != null;
+ },
+
+ toQueryString: function(object, base){
+ var queryString = [];
+
+ Object.each(object, function(value, key){
+ if (base) key = base + '[' + key + ']';
+ var result;
+ switch (typeOf(value)){
+ case 'object': result = Object.toQueryString(value, key); break;
+ case 'array':
+ var qs = {};
+ value.each(function(val, i){
+ qs[i] = val;
+ });
+ result = Object.toQueryString(qs, key);
+ break;
+ default: result = key + '=' + encodeURIComponent(value);
+ }
+ if (value != null) queryString.push(result);
+ });
+
+ return queryString.join('&');
+ }
+
+});
+
+})();
+
+
+
+
+/*
+---
+
+name: Browser
+
+description: The Browser Object. Contains Browser initialization, Window and Document, and the Browser Hash.
+
+license: MIT-style license.
+
+requires: [Array, Function, Number, String]
+
+provides: [Browser, Window, Document]
+
+...
+*/
+
+(function(){
+
+var document = this.document;
+var window = document.window = this;
+
+var ua = navigator.userAgent.toLowerCase(),
+ platform = navigator.platform.toLowerCase(),
+ UA = ua.match(/(opera|ie|firefox|chrome|version)[\s\/:]([\w\d\.]+)?.*?(safari|version[\s\/:]([\w\d\.]+)|$)/) || [null, 'unknown', 0],
+ mode = UA[1] == 'ie' && document.documentMode;
+
+var Browser = this.Browser = {
+
+ extend: Function.prototype.extend,
+
+ name: (UA[1] == 'version') ? UA[3] : UA[1],
+
+ version: mode || parseFloat((UA[1] == 'opera' && UA[4]) ? UA[4] : UA[2]),
+
+ Platform: {
+ name: ua.match(/ip(?:ad|od|hone)/) ? 'ios' : (ua.match(/(?:webos|android)/) || platform.match(/mac|win|linux/) || ['other'])[0]
+ },
+
+ Features: {
+ xpath: !!(document.evaluate),
+ air: !!(window.runtime),
+ query: !!(document.querySelector),
+ json: !!(window.JSON)
+ },
+
+ Plugins: {}
+
+};
+
+Browser[Browser.name] = true;
+Browser[Browser.name + parseInt(Browser.version, 10)] = true;
+Browser.Platform[Browser.Platform.name] = true;
+
+// Request
+
+Browser.Request = (function(){
+
+ var XMLHTTP = function(){
+ return new XMLHttpRequest();
+ };
+
+ var MSXML2 = function(){
+ return new ActiveXObject('MSXML2.XMLHTTP');
+ };
+
+ var MSXML = function(){
+ return new ActiveXObject('Microsoft.XMLHTTP');
+ };
+
+ return Function.attempt(function(){
+ XMLHTTP();
+ return XMLHTTP;
+ }, function(){
+ MSXML2();
+ return MSXML2;
+ }, function(){
+ MSXML();
+ return MSXML;
+ });
+
+})();
+
+Browser.Features.xhr = !!(Browser.Request);
+
+// Flash detection
+
+var version = (Function.attempt(function(){
+ return navigator.plugins['Shockwave Flash'].description;
+}, function(){
+ return new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
+}) || '0 r0').match(/\d+/g);
+
+Browser.Plugins.Flash = {
+ version: Number(version[0] || '0.' + version[1]) || 0,
+ build: Number(version[2]) || 0
+};
+
+// String scripts
+
+Browser.exec = function(text){
+ if (!text) return text;
+ if (window.execScript){
+ window.execScript(text);
+ } else {
+ var script = document.createElement('script');
+ script.setAttribute('type', 'text/javascript');
+ script.text = text;
+ document.head.appendChild(script);
+ document.head.removeChild(script);
+ }
+ return text;
+};
+
+String.implement('stripScripts', function(exec){
+ var scripts = '';
+ var text = this.replace(/