- <!doctype html>
- <script>(function(undefined){
- var recentDelimiter,
- nativeIndexOf = Array.prototype.indexOf,
- hasOwn = Object.prototype.hasOwnProperty,
- toString = Object.prototype.toString,
- isPrototypeOf = Object.prototype.isPrototypeOf,
- prototypeProperty = 'isPrototypeOf',
- types = "Number String Function Array Date RegExp Object".split(" "),
- class2type = [];
- for(var i=0,l=types.length,name;i<l;i++){
- name = types[i];
- class2type[ "[object " + name + "]" ] = name;
- }
- var indexOf = function(array, item) {
- if (array == undefined) return -1;
- var i, l;
- if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
- for (i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
- return -1;
- }
- var prototypeDelimiter = function(arg){
- if((arg===undefined || arg===0 ) && recentDelimiter){
- // Allow for shorthand [$](0) chaining
- if(arg===0)arg=init(this,recentDelimiter).chain();
- else arg=init(this,recentDelimiter);
- recentDelimiter = false;
- return arg;
- }else{
- return isPrototypeOf.call(this,arg);
- }
- }
- try{
- /*
- * Check for Object.defineProperty support
- * before adding property to Object.prototype
- * IE8 only supports Object.defineProperty on
- * DOM Objects
- */
- var defineProperty = {
- value: prototypeDelimiter,
- writable: true,
- enumerable: false,
- configurable: true
- };
- if(Object.defineProperty){
- var fn = function(){};
- Object.defineProperty(fn.prototype,"__delimit__",defineProperty);
- for(var i in (new fn)){
- if(i==='__delimit__'){
- throw '__delimt__ found on fn';
- }
- }
- isPrototypeOf = Object.prototype.__delimiter__ || isPrototypeOf;
- Object.defineProperty(Object.prototype,"__delimit__",defineProperty);
- prototypeProperty = '__delimit__';
- }else{
- throw 'Object.defineProperty doesn\' exist';
- }
- }catch(error){
- /*
- * Internet Explorer requires workaround to get
- * onto Object.prototype chain.
- * This page: http://jsbin.com/ehaziv/3 tests
- * for `isPrototypeOf` overiding support.
- * isPrototypeOf's fuctionality is 100% preserved
- * isPrototypeOf is also the least used Object.prototype
- * it isn't even ever used in jQuery, Prototype...
- */
- Object.prototype.isPrototypeOf = prototypeDelimiter;
- }
- /*
- * Make an Object into a 'delimitertoString'
- */
- function delimit(newDelimiter,parentDelimiter){
- /*
- * Objects and functions are stored as a tree
- * on the delimitertoString to allow proper garbage collection
- * everything should inherit from fns[0]
- *
- * ojbs ['Object',obj1,obj2..]
- * /
- * obj.toString
- * \
- * fns [ObjectFn,fn1,fn2...]
- */
- var delimitertoString = newDelimiter.toString = function(){
- recentDelimiter = this;
- return prototypeProperty;
- };
- // ObjectFn
- var fn = addFn();
- var parentDelimitertoString;
- if(parentDelimiter){
- parentDelimitertoString = parentDelimiter.toString;
- fn.prototype = new parentDelimitertoString.fns[0];
- }
- delimitertoString.objs =
- ( parentDelimitertoString && parentDelimitertoString.objs.slice(0) )
- || ['Object'];
- delimitertoString.fns = [fn];
- var i = 1,obj;
- while(obj=delimitertoString.objs[i++]){
- var fn = addFn(delimitertoString);
- if(parentDelimitertoString){
- var parentFn = parentDelimitertoString.fns[i-1].prototype;
- for(var i in parentFn){
- fn.prototype[i]=parentFn[i];
- }
- }
- }
- return newDelimiter;
- }
- /*
- * Add new function to delimitertoString
- */
- function addFn(delimitertoString,constructor){
- // The current obj is stored on `__` so it will
- // appear at the top of the list in console
- var fn = function(a){this.__=a;};
- /*
- * delimitertoString and Obj are Optional
- */
- if(constructor){
- if(constructor.name){
- var i = indexOf(types,constructor.name);
- if(-1!=i){
- constructor = types[i];
- }
- }
- delimitertoString.objs.push(constructor);
- }
- if(delimitertoString){
- delimitertoString.fns.push(fn);
- fn.prototype = new delimitertoString.fns[0];
- }
- fn.prototype.chain = function(){this.__chain__=true;return this;}
- fn.prototype.end = function(){return this.__;}
- return fn;
- }
- /*
- * Find the correct function in delimitertoString.fns
- * based on an a contsructor or obj
- * constructor may also be "Array,String,RegExp,Object,Date,Function"
- * findFn(delimitertoString,null,obj) is to allow for cross frame lookup
- * of native host objects
- */
- function findFn(delimitertoString,constructor,obj){
- var i;
- // When called from init
- if(obj!=undefined){
- if(indexOf(types,obj.constructor.name)!=-1){
- constructor = class2type[toString.call(obj)]
- }else{
- constructor = obj.constructor;
- }
- i = indexOf(delimitertoString.objs,constructor);
- }else{
- i = indexOf(delimitertoString.objs,constructor.name);
- if(i==-1){
- indexOf(delimitertoString.objs,constructor);
- }
- }
- return delimitertoString.fns[i];
- }
- /*
- * Each Object,Array,String,etc
- * has one fn that stores the
- * prototype for the Object
- */
- function ret(obj,fn){
- return fn.__chain__ ? init(obj,fn.__delimitertoString__).chain() : obj;
- }
- function addPrototype(delimiter,constructor,name,method){
- /*
- * To support live inheritance, all prototypes
- * added to Object are copied over to each prototype
- * and marked with object flag. The flag tells the script
- * it is safe to overide later(to simulate inheritance)
- * any other protypes added to an Object must also copy
- * over all `Object.prototype`s on creation
- * This means adding 'Object' prototypes are slighly more
- * expensive, but should be used sparingly to begin with
- */
- var fn = findFn(delimiter.toString,constructor) || addFn(delimiter.toString,constructor);
- fn.prototype[name] = function(){
- var apply = method.apply(this.__,arguments);
- return apply===undefined?apply:ret(apply,this);
- }
- }
- /*
- * runs when delimitertoString is called
- * on object example: object[$]()
- */
- function init(obj,delimiter){
- // fn contains `Object`s proxied prototype
- var fn = findFn(delimiter.toString,undefined,obj) || delimiter.toString.fns[0];
- var ret = new fn(obj);
- // Store reference to delimitertoString in case of chaining
- ret.__delimitertoString__ = delimiter.toString;
- if(class2type[toString.call(obj)=='Function'] || indexOf(types,obj.name)){
- //console.log(delimiter);
- ret.fn = function(o){
- for(var i in o){
- addPrototype(delimiter,obj,i,o[i]);
- }
- }
- }
- return ret;
- }
- window.delimit = delimit;
- // Allow for jQuery, Mootools, Zepto, Prototype... to continue to use '$' variable
- delimit(window.$ || (window.$ = {}));
- })();
- Array[$]().fn({
- indexOf:function(array){
- console.log('indexOf');
- }
- });
- var fn = function(){};
- var f = new fn;
- fn[$]().fn({
- test:function(){
- return 'test'
- }
- });
- Object[$]().fn({
- log:function(){
- console.log(this);
- }
- });
- f
- [$]().test()
- [$]().log();
- var o = {};
- delimit(o,$);
- Array[o]().fn({
- indexOf:function(array){
- console.log('indexOf override!');
- },
- yo:function(){alert('yo')}
- });
- var array = [1,2,3];
- array[o]().indexOf(2);
- </script>