Skip to content

Instantly share code, notes, and snippets.

@JustinSDK
Last active December 15, 2015 02:09
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JustinSDK/5185336 to your computer and use it in GitHub Desktop.
Save JustinSDK/5185336 to your computer and use it in GitHub Desktop.
The Example of "JavaScript Essence: Writing an Ajax Library"

The Example of JavaScript Essence: Writing an Ajax Library

(function(global) {
    var XD = function(selector, container) {
        return new XD.mth.init(selector, container);
    };
    
    var utils = {
        trim: function(text) {
  	    return (text || '').replace( /^(\s|\u00A0)+|(\s|\u00A0)+$/g, '');
	    },
        isArray: function(obj) {
		    return Object.prototype.toString.call(obj) === '[object Array]';
	    },
        isFunction: function(obj) {
		    return Object.prototype.toString.call(obj) === '[object Function]';
	    },
        each: function(obj, callback) {
            var length = obj.length,
                isObj = (length === undefined) || this.isFunction(obj);
            if (isObj) {
				for(var name in obj) {
					if(callback.call(obj[name], obj[name], name) === false ) {
						break;
					}
				}
			}
            else {
				for(var i = 0, value = obj[0];
					i < length && callback.call(obj[i], value, i) !== false; value = obj[++i] ) {}
			}
            return obj;
        },
        makeArray: function(arrayLike) {
			if(arrayLike.length != null) {
                return Array.prototype.slice.call(arrayLike, 0)
                             .filter(function(ele) { return ele !== undefined; });
			}
            return [];
		},
        screen: function() {
            return {
                width: screen.width,
                height: screen.height,
                availWidth: screen.availWidth,
                availHeight: screen.availHeight
            };
        },
        window: function() {
            var xywh = {};
            if(window.screenX) {
                 xywh.x = window.screenX;
                 xywh.y = window.screenY;
            }
            else if(window.screenLeft) {
                xywh.x = window.screenLeft;
                xywh.y = window.screenTop;
            }
            
            if(window.outerWidth) {
                xywh.width = window.outerWidth;
                xywh.height = window.outerHeight;
            }
            else if(document.documentElement.offsetWidth) {
                xywh.width = document.documentElement.offsetWidth;
                xywh.height = document.documentElement.offsetHeight;
            }
            else if(document.body.offsetWidth) {
                xywh.width = document.body.offsetWidth;
                xywh.height = document.body.offsetHeight;
            }
            return xywh;
        },
        viewport: function() {
            var wh = {};
            if(window.innerWidth) {
                wh.width = window.innerWidth;
                        wh.height = window.innerHeight;
            }
            else if(document.documentElement.clientWidth) {
                wh.width = document.documentElement.clientWidth;
                wh.height = document.documentElement.clientHeight;
            }
            else if(document.body.clientWidth) {
                wh.width = document.body.clientWidth;
                wh.height = document.body.clientHeight;
            }
            return wh;            
        },
        scroll: function() {
            var xy = {};
            if(window.pageXOffset) {
                xy.x = window.pageXOffset;
                xy.y = window.pageYOffset;
            }
            else if(document.documentElement.srollLeft) {
                xy.x = document.documentElement.srollLeft;
                xy.y = document.documentElement.srollTop;
            }
            else if(document.body.srollLeft) {
                xy.x = document.body.srollLeft;
                xy.y = document.body.srollTop;
            }
            return xy;        
        },
        param: function(data) {
            var pairs = [];
            for(var name in data) {
                var pair = encodeURIComponent(name) + '=' + 
                           encodeURIComponent(data[name]);
                pairs.push(pair.replace('/%20/g', '+'));
            }
            return pairs.join('&');
        },
        xhr: window.XMLHttpRequest && 
                      (window.location.protocol !== 'file:' 
                          || !window.ActiveXObject) ?
                       function() {
                           return new XMLHttpRequest();
                       } :
                       function() {
                          try {
                             return new ActiveXObject('Microsoft.XMLHTTP');
                          } catch(e) {
                             throw new Error('XMLHttpRequest not supported');
                          }
                       },
        ajax: function(option) {
            option.header = option.header || {
              'Content-Type':'application/x-www-form-urlencoded'};
            option.callback = option.callback || function() {};
            
            if(!option.url || !option.method) {
                return;
            }
                    
            var request = utils.xhr();
            request.onreadystatechange = function() {
                option.callback.call(request, request);
            };
                    
            var body = null;
            var url = option.url;
            if(option.data) {
                if(option.method === 'POST') {
                    body = utils.param(option.data);
                }
                else {
                    url = option.url + '?' + utils.param(option.data) 
                             + '&time=' + new Date().getTime();
                }
            }
                    
            request.open(option.method, url);
            for(var name in option.header) {
                request.setRequestHeader(name, option.header[name]);
            }
            request.send(body);        
        },
        request: function(method, url, parameters, callback, type) {
            utils.ajax({
                method   : method,
                url      : url,
                data     : parameters,
                callback : function(request) {
                    if(request.readyState === 4) {
                        var result;
                        if(type === 'xml') {
                            result = request.responseXML;
                        }
                        else if(type === 'json') {
                            result = eval(request.responseText);
                        }
                        else {
                            result = request.responseText;
                        }
                        if(callback) {
                            callback(result, request.status, request);
                        }
                    }
                }
            });
        },
        get: function(url, parameters, callback, type) {
            utils.request('GET', url, parameters, callback, type);
        },
        post: function(url, parameters, callback, type) {
            utils.request('POST', url, parameters, callback, type);
        },
        getScript: function(url, callback) {
            var script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = url;
            script.onload = script.onreadystatechange = function() {
                if (!this.readyState ||
                    this.readyState === "loaded" || 
                    this.readyState === "complete") {
                    this.onload = this.onreadystatechange = null;
                    document.getElementsByTagName('head')[0].removeChild(this);
                    if(callback) { 
                        callback();
                    }
                }
            };
                    
            document.getElementsByTagName('head')[0].appendChild(script);
        },
        jsonp: function(option, callbackName) {
            if(!option.url || !callbackName) {
                return;
            }
            var data = option.data || {};
                    
            data[callbackName] = 'XD' + arguments.callee.jsc++;
            window[data[callbackName]] = function(json) {
                option.callback(json);
            };
            var url = option.url + '?' + utils.param(data);
                    
            utils.getScript(url, function() {
                 window[data[callbackName]] = undefined;
                 try {
                     delete window[data[callbackName]];
                 }
                 catch(e) {}
            });        
        }
    };
    
    utils.jsonp.jsc = new Date().getTime();
    
    XD.Event = function(original) {
        if(!this.stopPropagation) {
            return new XD.Event(original);
        }
        this.original = original;
        this.type = original.type;
        this.target = original.target || original.srcElement;
    };
    
    XD.Event.prototype = {
        stopPropagation: function() {
            if(this.original.stopPropagation) {
                this.original.stopPropagation();
            }
            else {
                this.original.cancelBubble = true;
            }
        }
    };
    
    if(document.addEventListener) {
        utils.bind = function(element, eventType, handler) {
            element.addEventListener(eventType, function(event) {
                var result = handler.call(event.currentTarget, XD.Event(event));
                if(result === false) {
                    event.preventDefault();
                }
                return result;
            }, false);
        };
        utils.unbind = function(element, eventType, handler) {
            element.removeEventListener(eventType, handler, false);
        };
    }
    else if(document.attachEvent) {
        utils.bind = function(element, eventType, handler) {
            element.attachEvent('on' + eventType, function() {
                var result = handler.call(element, XD.Event(window.event));
                if(result === false) {
                    window.event.returnValue = false;
                }
                return result;
            });
        };
        utils.unbind = function(element, eventType, handler) {
            element.detachEvent(eventType, handler);
        };
    }
    
   function extend(target, source) {
        utils.each(source, function(value, key) {
            target[key] = value;
        });
   }
   
   extend(XD, utils);
   XD.extend = extend;
   XD.props = {
        'for': 'htmlFor',
        'class': 'className',
        readonly: 'readOnly',
        maxlength: 'maxLength',
        cellspacing: 'cellSpacing',
        rowspan: 'rowSpan',
        colspan: 'colSpan',
        tabindex: 'tabIndex',
        usemap: 'useMap',
        frameborder: 'frameBorder'
    };
   
   XD.mth = XD.prototype = {
       init: function(selector, container) {
           if(selector.nodeType) {
               this[0] = selector;
               this.length = 1;
               return this;
           }
           
           if(container && container[0]) {
               container = container[0];
           }
           else {
               container = document;
           }
           
           var elements = [];
           XD.each(selector.split(','), function(text) {
               text = XD.trim(text);
               if(text.charAt(0) === '#') {
                   elements.push(container.getElementById(text.substring(1)));
               }
               else if(text.charAt(0) === '<') {
                   elements.push(document.createElement(text.substring(1, text.length - 1)));
               }
               else {
                   XD.each(container.getElementsByTagName(text), function(element) {
                       elements.push(element);
                   });
                   
               }
           });
           XD.extend(this, elements);
           this.length = elements.length;
       },
       size: function() {
           return this.length;
       },
       isEmpty: function() {
           return this.length === 0;
       },
       each: function(callback) {
           return XD.each(this, callback);
       },
       html: function(value) {
           if(value === undefined) {
               return this[0] && this[0].nodeType === 1 ?
				        this[0].innerHTML : null;
           }
           else {
               return XD.each(this, function(element) {
                   if(element.nodeType === 1) {
                       element.innerHTML = value;
                   }
               });
           }
       },
       attr: function(name, value) {
           name = XD.props[name] || name;
           if(value === undefined) {
               if(typeof name === 'string') {
                   return this[0] && this[0].nodeType !== 3 && this[0].nodeType !== 8 ?
                        this[0][name] : undefined;
               }
               else {
                  XD.each(this, function(element) {
                      if(element.nodeType !== 3 && element.nodeType !== 8) {
                          XD.each(name, function(optValue, optName) {
                              optName = XD.props[optName] || optName;
                              element[optName] = optValue;
                          });
                      }
                  });
                  return this; 
               }               
           }
           else {
               return XD.each(this, function(element) {
                   if(element.nodeType !== 3 && element.nodeType !== 8) {
                       element[name] = value;
                   }
               });
           }       
       },
       val: function(value) {
           if(value === undefined) {
               return this[0] && this[0].nodeName === 'INPUT' ? 
                       this[0].value : null;
           }
           else {
               return XD.each(this, function(element) {
                   if(element.nodeName === 'INPUT') {
                       element.value = value;
                   }
               });
           }
       },
       append: function(childs) {
           if(typeof childs === 'string' || childs.nodeType) {
               childs = XD(childs);
           }
           
           if(this.length === 1) {
               var parent = this[0];
               XD.each(childs, function(child) {
                   parent.appendChild(child);
               });
           }
           else if(this.length > 1){
               XD.each(this, function(parent) {
                   childs.each(function(child) {
                       var container = document.createElement('div');
                       container.appendChild(child);
                       container.innerHTML = container.innerHTML;
                       parent.appendChild(container.firstChild);
                   });
               });
           }
           return this;
       },
       appendTo: function(parents) {
           if(typeof parents === 'string' || parents.nodeType) {
               parents = XD(parents);
           }
           return parents.append(this);
       },
       remove: function() {
           return XD.each(this, function(element) {
               element.parentNode.removeChild(element);
           });
       },
       removeChilds: function() {
           return XD.each(this, function(element) {
               var length = element.childNodes.length;
               for(var i = 0; i < length; i++) {
                   element.removeChild(element.firstChild);
               }
           });
       },
       bind: function(eventType, handler) {
           return XD.each(this, function(element) {
               XD.bind(element, eventType, handler);
           });
       },
       unbind: function(eventType, handler) {
           return XD.each(this, function(element) {
               XD.unbind(element, eventType, handler);
           });
       },
       click: function(handler) {
           return this.bind('click', handler);
       },
       blur: function(handler) {
           return this.bind('blur', handler);
       },
       change: function(handler) {
           return this.bind('change', handler);
       },
       keyup: function(handler) {
           return this.bind('keyup', handler);
       },
       css: function(name, value) {
           name = XD.props[name] || name;
           if(value === undefined) {
               if(typeof name === 'string') {
                   if(this[0] && this[0].nodeType !== 3 && this[0].nodeType !== 8) {
                       if(window.getComputedStyle) {
                            return window.getComputedStyle(this[0], null)[name];
                       }
                       else if(this[0].currentStyle) {
                            return this[0].currentStyle[name];
                       }
                       else {
                           return undefined;
                       }                   
                   }
               }
               else {
                  XD.each(this, function(element) {
                      if(element.nodeType !== 3 && element.nodeType !== 8) {
                          XD.each(name, function(optValue, optName) {
                              optName = XD.props[optName] || optName;
                              element.style[optName] = optValue;
                          });
                      }
                  });
                  return this; 
               }               
           }
           else {
               return XD.each(this, function(element) {
                   if(element.nodeType !== 3 && element.nodeType !== 8) {
                       element.style[name] = value;
                   }
               });
           }       
       },
       width: function(value) {
           return this.css('width', value);
       },
       height: function(value) {
           return this.css('height', value);
       },
       offset: function() {
           if(this[0]) {
               var left = 0;
               var top = 0;
               for(var e = this[0]; e; e = e.offsetParent) {
                   left += e.offsetLeft;
                   top += e.offsetTop;
               }

               for(var e = this[0].parentNode; e && e != document.body; e = e.parentNode) {
                   if(e.scrollLeft) {
                       left -= e.scrollLeft;
                   }
                   if(e.scrollTop) {
                       top -= e.scrollTop;
                   }
               }      

               return {
                   left: left,
                   top: top,
                   offsetWidth : this[0].offsetWidth,
                   offsetHeight : this[0].offsetHeight
               };
           }
       },
       hide: function() {
           return XD.each(this, function(element) {
               var elementXD = XD(element);
               element.previousDisplay = elementXD.css('display');
               element.style.display = 'none';
           });
       },
       show: function() {
           return XD.each(this, function(element) {
               var elementXD = XD(element);
               element.style.display = element.previousDisplay || '';
               if(elementXD.css('display') === 'none') {
                   var node = document.createElement(element.nodeName);
                   document.body.appendChild(node);
                   element.style.display = XD(node).css('display');
                   document.body.removeChild(node);
               }
           });
       },
       opacity: function(value) {
            if(value === undefined) {
                var opt = this.css('opacity') || this.css('filter');
                if(opt === '') {
                    return 1;
                }
                if(opt.indexOf('alpha') !== -1)  {
                    return opt.substring(14, opt.length - 1) / 100;
                }
                return parseFloat(opt);
            }
            else {
                return XD.each(this, function(element) {
                    if(XD(element).css('opacity') !== undefined) {
                        element.style.opacity = value;
                    }
                    else {
                        element.style.filter = 
                           'alpha(opacity=' + parseInt(value * 100) + ')';
                    }                           
                });
            }
       },
       fadeIn: function(speed) {
            speed = speed || 5000;
            return XD.each(this, function(element) {
                var target = element.previousOpacity || 1;
                delete element.previousOpacity;
                var step = target / speed * 500;
                var opt = 0;
                setTimeout(function next() {
                    opt += step;
                    if(opt < target) {
                        XD(element).opacity(opt);
                        setTimeout(next);
                    }
                    else {
                        XD(element).opacity(target);
                    }
                }, 500);       
            });
       },
       fadeOut: function(speed) {
           speed = speed || 5000;
           return XD.each(this, function(element) {
               var elementXD = XD(element);
               element.previousOpacity = elementXD.opacity();
               var step = element.previousOpacity / speed * 500;
               var opt = element.previousOpacity;
               setTimeout(function next() {
                   opt -= step;
                   if(opt > 0) {
                       elementXD.opacity(opt);
                       setTimeout(next);
                   }
                   else {
                       elementXD.opacity(0);
                   }
               }, 500);       
           });
       },
       hasClass: function(clz) {
           if(this[0]) {
               var clzs = this[0].className;
               if(!clzs) {
                    return false;
               }
               if(clzs === clz) {
                    return true;
               }
               return clzs.search('\\b' + clz + '\\b') !== -1;
           }
           return false;
       },
       addClass: function(clz) {
           return XD.each(this, function(element) {
               if(!XD(element).hasClass(clz)) {
                   if(element.className) {
                       clz = ' ' + clz;
                   }
                   element.className += clz;
               }           
           });
       },
       removeClass: function(clz) {
           return XD.each(this, function(element) {
               element.className = element.className.replace(
                        new RegExp('\\b' + clz + '\\b\\s*', 'g'), '');
           });
       },
       toggleClass: function(clz1, clz2) {
           return XD.each(this, function(element) {
               var elementXD = XD(element);
               if(elementXD.hasClass(clz1)) {
                   elementXD.removeClass(clz1);
                   elementXD.addClass(clz2);
               }
               else if(elementXD.hasClass(clz2)) {
                   elementXD.removeClass(clz2);
                   elementXD.addClass(clz1);
               }
           });
       }
   };  

   XD.mth.init.prototype = XD.mth;

   global.XD = XD;
})(this);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment