jquery插件

下面是对Jquery几个经常用到的地方进行的增强。

功能是参考百度七巧板JS框架来完成的。

一、页面属性

$.page.getHeight():获取页面高度

$.page.getWidth():获取页面宽度
$.page.createStyleSheet(options):在页面中创建样式表对象
$.page.getScrollTop():获取纵向滚动量
$.page.getScrollLeft():获取横向滚动量
$.page.getViewHeight():获取页面视觉区域高度
$.page.getViewWidth():获取页面视觉区域宽度
$.page.getMousePosition(element):获得页面里的目前鼠标所在的坐标
$.page.getPosition(element):获取目标元素相对于整个文档左上角的位置
$.page.lazyLoadImage(options):延迟加载图片. 默认只加载可见高度以上的图片, 随着窗口滚动加载剩余图片.注意: 仅支持垂直方向.
$.page.loadCssFile(path):动态在页面上加载一个外部css文件
$.page.loadJsFile(path):动态在页面上加载一个外部js文件
$.page.load(resources, options, ignoreAllLoaded):加载一组资源,支持多种格式资源的串/并行加载,支持每个文件有单独回调函数。

二、浏览器判断
$.browser.ie
$.browser.firefox
$.browser.chrome
$.browser.isGecko
$.browser.isWebkit
$.browser.isStrict
$.browser.opera
$.browser.safari



三、平台判断
$.platform.isAndroid
$.platform.isIpad
$.platform.isIphone
$.platform.isMacintosh
$.platform.isWindows
$.platform.isX11



四、字符串处理
$.string.decodeHTML(source):对目标字符串进行html解码
$.string.encodeHTML(source):对目标字符串进行html编码
$.string.stripTags(source):去掉字符串中的html标签
$.string.escapeReg(source):将目标字符串中可能会影响正则表达式构造的字符串进行转义。
$.string.trim(source):删除目标字符串两端的空白字符



五、类型
$.lang.guid():返回一个当前页面的唯一标识字符串。
$.lang.isFunction(source):判断目标参数是否为function或Function实例
$.lang.isElement(source):判断目标参数是否为Element对象
$.lang.isArray(source):判断目标参数是否Array对象



六、数组
$.array.indexOf(source, match, fromIndex):查询数组中指定元素的索引位置
$.array.contains(source, obj):判断一个数组中是否包含给定元素
$.array.empty(source):清空一个数组
$.array.lastIndexOf(source, match, fromIndex):从后往前,查询数组中指定元素的索引位置
$.array.map(source, iterator, thisObject):遍历数组中所有元素,将每一个元素应用方法进行转换,并返回转换后的新数组。
$.array.reduce(source, iterator, initializer):遍历数组中所有元素,将每一个元素应用方法进行合并,并返回合并后的结果。
$.array.remove(source, match):移除数组中的项
$.array.removeAt(source, index):移除数组中的项
$.array.unique(source, compareFn):过滤数组中的相同项。如果两个元素相同,会删除后一个元素。



七、cookie
$.cookie.getRaw(key):获取cookie的值,不对值进行解码
$.cookie.setRaw(key, value, options):设置cookie的值,不对值进行编码
$.cookie.remove(key, options):删除cookie的值
$.cookie.get(key):获取cookie的值,用decodeURIComponent进行解码
$.cookie.set(key, value, options):设置cookie的值,用encodeURIComponent进行编码



八、整数
$.number.comma(source, length):为目标数字添加逗号分隔
$.number.randomInt(min, max):生成随机整数,范围是[min, max]
$.number.pad(source, length):对目标数字进行0补齐处理



九、日志
$.sio.log(url):通过请求一个图片的方式令服务器存储一条日志,常用于记录用户点击位置,进行分析统计



十、URL
$.url.escapeSymbol(source):对字符串进行%#&+=以及和\s匹配的所有字符进行url转义
$.url.getQueryValue(url, key):根据参数名从目标URL中获取参数值
$.url.jsonToQuery(json, replacer_opt):将json对象解析成query字符串

$.url.queryToJson(url):解析目标URL中的参数成json对象


插件源码:

;(function($){
	$.extend({
		hasClass:function(targetClassName){
			var className = $(this).attr("class");
			var classArray = className.split(" ");
			if(className && classArray.length == 0){
				if(targetClassName == className) return true;
			}else if(className && classArray.length > 0){
				for(var i=0; i<=classArray.length-1; i++){
					if(classArray[i] == targetClassName) return true;
				}
			}

			return false;
		},
		
		getDocument:function (element) {
			return $.lang.isElement(element) ? element : element.ownerDocument || element.document;
		}
	});
})(jQuery);

;(function($){
	$.lang = $.lang || {};
	
	$.lang.isFunction = function (source) {
	    // chrome下,'function' == typeof /a/ 为true.
	    return '[object Function]' == Object.prototype.toString.call(source);
	};
	
	$.lang.isString = function (source) {
	    return '[object String]' == Object.prototype.toString.call(source);
	};
})(jQuery);

;(function($){
	
	$.page = $.page || {};
	$.page.xy = {x:0, y:0};//当前鼠标坐标

	$.page.getHeight = $.page.getHeight || function(){
		var doc = document,
        body = doc.body,
        html = doc.documentElement,
        client = doc.compatMode == 'BackCompat' ? body : doc.documentElement;

		return Math.max(html.scrollHeight, body.scrollHeight, client.clientHeight);
	};

	$.page.getWidth  = $.page.getWidth || function () {
		var doc = document,
        body = doc.body,
        html = doc.documentElement,
        client = doc.compatMode == 'BackCompat' ? body : doc.documentElement;

		return Math.max(html.scrollWidth, body.scrollWidth, client.clientWidth);
	};

	$.page.createStyleSheet = $.page.createStyleSheet || function(options){
		var op = options || {},
			doc = op.document || document,
			s;

		if ($.browser.ie) {
			//修复ie下会请求一个undefined的bug  berg 2010/08/27 
			if(!op.url)
				op.url = "";
			return doc.createStyleSheet(op.url, op.index);
		} else {
			s = "<style type='text/css'></style>";
			op.url && (s="<link type='text/css' rel='stylesheet' href='"+op.url+"'/>");
			$("HEAD:eq(0)").after(s);
		}
	};

	$.page.getScrollTop =  $.page.getScrollTop || function(){
		var d = document;
		return window.pageYOffset || d.documentElement.scrollTop || d.body.scrollTop;
	};

	$.page.getScrollLeft= $.page.getScrollLeft || function () {
		var d = document;
		return window.pageXOffset || d.documentElement.scrollLeft || d.body.scrollLeft;
	};

	$.page.getViewHeight = $.page.getViewHeight || function () {
		var doc = document,
			client = doc.compatMode == 'BackCompat' ? doc.body : doc.documentElement;

		return client.clientHeight;
	};

	$.page.getViewWidth = function () {
		var doc = document,
			client = doc.compatMode == 'BackCompat' ? doc.body : doc.documentElement;

		return client.clientWidth;
	};
	
	$(document).bind("mousemove", function(e){
		e = window.event || e;
		$.page.xy.x = e.clientX;
		$.page.xy.y = e.clientY;
		//console.log(e.clientX+","+e.clientY);
	});

	$.page.getMousePosition = $.page.getMousePosition || function(){
		return {
			x : $.page.getScrollLeft() + $.page.xy.x,
			y : $.page.getScrollTop() + $.page.xy.y
		};
	};

	/**
	 * 获取目标元素相对于整个文档左上角的位置
	 * @grammar $.dom.getPosition(element)
	 * @param {HTMLElement|string} element 目标元素或目标元素的id
	 *             
	 * @returns {Object} 目标元素的位置,键值为top和left的Object。
	 */
	$.page.getPosition = function (element) {
		var doc = $.getDocument(element),
			browser = $.browser
		// Gecko 1.9版本以下用getBoxObjectFor计算位置
		// 但是某些情况下是有bug的
		// 对于这些有bug的情况
		// 使用递归查找的方式
			BUGGY_GECKO_BOX_OBJECT = browser.isGecko > 0 && 
									 doc.getBoxObjectFor &&
									 $(element).css('position') == 'absolute' &&
									 (element.style.top === '' || element.style.left === ''),
			pos = {"left":0,"top":0},
			viewport = (browser.ie && !browser.isStrict) ? doc.body : doc.documentElement,
			parent;
		var box;
		
		if(element == viewport){
			return pos;
		}

		if(element.getBoundingClientRect){ // IE and Gecko 1.9+
			//当HTML或者BODY有border width时, 原生的getBoundingClientRect返回值是不符合预期的
			//考虑到通常情况下 HTML和BODY的border只会设成0px,所以忽略该问题.
			doc = document;
			box = element.getBoundingClientRect();

			pos.left = Math.floor(box.left) + Math.max(doc.documentElement.scrollLeft, doc.body.scrollLeft);
			pos.top  = Math.floor(box.top)  + Math.max(doc.documentElement.scrollTop,  doc.body.scrollTop);
			
			// IE会给HTML元素添加一个border,默认是medium(2px)
			// 但是在IE 6 7 的怪异模式下,可以被html { border: 0; } 这条css规则覆盖
			// 在IE7的标准模式下,border永远是2px,这个值通过clientLeft 和 clientTop取得
			// 但是。。。在IE 6 7的怪异模式,如果用户使用css覆盖了默认的medium
			// clientTop和clientLeft不会更新
			pos.left -= doc.documentElement.clientLeft;
			pos.top  -= doc.documentElement.clientTop;
			
			var htmlDom = doc.body,
				// 在这里,不使用element.style.borderLeftWidth,只有computedStyle是可信的
				htmlBorderLeftWidth = parseInt($(htmlDom).css('borderLeftWidth')),
				htmlBorderTopWidth = parseInt($(htmlDom).css('borderTopWidth'));
			if(browser.ie && !browser.isStrict){
				pos.left -= isNaN(htmlBorderLeftWidth) ? 2 : htmlBorderLeftWidth;
				pos.top  -= isNaN(htmlBorderTopWidth) ? 2 : htmlBorderTopWidth;
			}
		/*
		 * 因为firefox 3.6和4.0在特定页面下(场景待补充)都会出现1px偏移,所以暂时移除该逻辑分支
		 * 如果 2.0版本时firefox仍存在问题,该逻辑分支将彻底移除. by rocy 2011-01-20
		} else if (doc.getBoxObjectFor && !BUGGY_GECKO_BOX_OBJECT){ // gecko 1.9-

			// 1.9以下的Gecko,会忽略ancestors的scroll值
			// https://bugzilla.mozilla.org/show_bug.cgi?id=328881 and
			// https://bugzilla.mozilla.org/show_bug.cgi?id=330619

			box = doc.getBoxObjectFor(element);
			var vpBox = doc.getBoxObjectFor(viewport);
			pos.left = box.screenX - vpBox.screenX;
			pos.top  = box.screenY - vpBox.screenY;
			*/
		} else { // safari/opera/firefox
			parent = element;

			do {
				pos.left += parent.offsetLeft;
				pos.top  += parent.offsetTop;
				// safari里面,如果遍历到了一个fixed的元素,后面的offset都不准了
				if (browser.isWebkit > 0 && $(parent).css('position') == 'fixed') {
					pos.left += doc.body.scrollLeft;
					pos.top  += doc.body.scrollTop;
					break;
				}
				
				parent = parent.offsetParent;
			} while (parent && parent != element);

			// 对body offsetTop的修正
			if(browser.opera > 0 || (browser.isWebkit > 0 && $(parent).css('position') == 'absolute')){
				pos.top  -= doc.body.offsetTop;
			}

			// 计算除了body的scroll
			parent = element.offsetParent;
			while (parent && parent != doc.body) {
				pos.left -= parent.scrollLeft;
				// see https://bugs.opera.com/show_bug.cgi?id=249965
	//            if (!b.opera || parent.tagName != 'TR') {
				if (!browser.opera || parent.tagName != 'TR') {
					pos.top -= parent.scrollTop;
				}
				parent = parent.offsetParent;
			}
		}

		return pos;
	};

	/**
	 * 延迟加载图片. 默认只加载可见高度以上的图片, 随着窗口滚动加载剩余图片.注意: 仅支持垂直方向.
	 * @grammar $.page.lazyLoadImage([options])
	 * @param {Object} options
	 * @param {String} [options.className] 延迟加载的IMG的className,如果不传入该值将延迟加载所有IMG.
	 * @param {Number} [options.preloadHeight] 预加载的高度, 可见窗口下该高度内的图片将被加载.
	 * @param {String} [options.placeHolder] 占位图url.
	 * @param {Function} [options.onlazyload] 延迟加载回调函数,在实际加载时触发.
	 */
	$.page.lazyLoadImage = function(options) {
		options = options || {};
		options.preloadHeight = options.preloadHeight || 0;

		$(document).ready(function() {
			var imgs = document.getElementsByTagName('IMG'),
					targets = imgs,
					len = imgs.length,
					i = 0,
					viewOffset = getLoadOffset(),
					srcAttr = 'data-tangram-ori-src',
					target;
			//避免循环中每次都判断className
			if (options.className) {
				targets = [];
				for (; i < len; ++i) {
					if ($(imgs[i]).hasClass(options.className)) {
						targets.push(imgs[i]);
					}
				}
			}
			//计算需要加载图片的页面高度
			function getLoadOffset() {
				return $.page.getScrollTop() + $.page.getViewHeight() + options.preloadHeight;
			}
			//加载可视图片
			for (i = 0, len = targets.length; i < len; ++i) {
				target = targets[i];
				if ($.page.getPosition(target).top > viewOffset) {
					target.setAttribute(srcAttr, target.src);
					options.placeHolder ? target.src = options.placeHolder : target.removeAttribute('src');
				}
			}
			//处理延迟加载
			var loadNeeded = function() {
				var viewOffset = getLoadOffset(),
					imgSrc,
					finished = true,
					i = 0,
					len = targets.length;
				for (; i < len; ++i) {
					target = targets[i];
					imgSrc = target.getAttribute(srcAttr);
					imgSrc && (finished = false);
					if ($.page.getPosition(target).top < viewOffset && imgSrc) {
						target.src = imgSrc;
						target.removeAttribute(srcAttr);
						$.lang.isFunction(options.onlazyload) && options.onlazyload(target);
					}
				}
				//当全部图片都已经加载, 去掉事件监听
				finished && $(window).unbind('scroll', loadNeeded);
			};

			$(window).bind('scroll', loadNeeded);
		});
	};

	/**
	 * 动态在页面上加载一个外部css文件
	 * @grammar $.page.loadCssFile(path)
	 * @param {string} path css文件路径
	 */
	$.page.loadCssFile = function (path) {
		var element = document.createElement("link");
		
		element.setAttribute("rel", "stylesheet");
		element.setAttribute("type", "text/css");
		element.setAttribute("href", path);

		document.getElementsByTagName("head")[0].appendChild(element);        
	};


	/**
	 * 动态在页面上加载一个外部js文件
	 * @grammar $.page.loadJsFile(path)
	 * @param {string} path js文件路径
	 */
	$.page.loadJsFile = function (path) {
		var element = document.createElement('script');

		element.setAttribute('type', 'text/javascript');
		element.setAttribute('src', path);
		element.setAttribute('defer', 'defer');

		document.getElementsByTagName("head")[0].appendChild(element);    
	};

	/**
	 *
	 * 加载一组资源,支持多种格式资源的串/并行加载,支持每个文件有单独回调函数。
	 *
	 * @name $.page.load
	 * @function
	 * @grammar $.page.load(resources[, options])
	 *
	 * @param {Array} resources               资源描述数组,单个resource含如下属性.
	 * @param {String} resources.url           链接地址.
	 * @param {String} [resources.type]        取值["css","js","html"],默认参考文件后缀.
	 * @param {String} [resources.requestType] 取值["dom","ajax"],默认js和css用dom标签,html用ajax.
	 * @param {Function} resources.onload        当前resource加载完成的回调函数,若requestType为ajax,参数为xhr(可能失效),responseText;若requestType为dom,无参数,执行时this为相应dom标签。.
	 *
	 * @param {Object} [options]               可选参数.
	 * @param {Function} [options.onload]        资源全部加载完成的回调函数,无参数。.
	 * @param {Boolean} [options.parallel]      是否并行加载,默认为false,串行。.
	 * @param {Boolean} [ignoreAllLoaded]       全部加载之后不触发回调事件.主要用于内部实现.
	 *
	 *
	 * @remark
	 *  //串行实例
	 *  baidu.page.load([
	 *      { url : "http://img.baidu.com/js/tangram-1.3.2.js" },
	 *      {url : "http://xxx.baidu.com/xpath/logicRequire.js",
	 *          onload : fnOnRequireLoaded
	 *      },
	 *      { url : "http://xxx.baidu.com/xpath/target.js" }
	 *  ],{
	 *      onload : fnWhenTargetOK
	 *  });
	 *  //并行实例
	 *  baidu.page.load([
	 *      {
	 *          url : "http://xxx.baidu.com/xpath/template.html",
	 *          onload : fnExtractTemplate
	 *      },
	 *      { url : "http://xxx.baidu.com/xpath/style.css"},
	 *      {
	 *          url : "http://xxx.baidu.com/xpath/import.php?f=baidu.*",
	 *          type : "js"
	 *      },
	 *      {
	 *          url : "http://xxx.baidu.com/xpath/target.js",
	 *      },
	 *      {
	 *          url : "http://xxx.baidu.com/xpath/jsonData.js",
	 *          requestType : "ajax",
	 *          onload : fnExtractData
	 *      }
	 *  ],{
	 *      parallel : true,
	 *      onload : fnWhenEverythingIsOK
	 * });
	 */
	$.page.load = function(resources, options, ignoreAllLoaded) {
	    options = options || {};
	    var self = $.page.load,
	        cache = self._cache = self._cache || {},
	        loadingCache = self._loadingCache = self._loadingCache || {},
	        parallel = options.parallel;

	    function allLoadedChecker() {
	        for (var i = 0, len = resources.length; i < len; ++i) {
	            if (! cache[resources[i].url]) {
	                setTimeout(arguments.callee, 10);
	                return;
	            }
	        }
	        options.onload();
	    };

	    function loadByDom(res, callback) {
	        var node, loaded, onready;
	        switch (res.type.toLowerCase()) {
	            case 'css' :
	                node = document.createElement('link');
	                node.setAttribute('rel', 'stylesheet');
	                node.setAttribute('type', 'text/css');
	                break;
	            case 'js' :
	                node = document.createElement('script');
	                node.setAttribute('type', 'text/javascript');
	                node.setAttribute('charset', res.charset || self.charset);
	                break;
	            case 'html' :
	                node = document.createElement('iframe');
	                node.frameBorder = 'none';
	                break;
	            default :
	                return;
	        }

	        // HTML,JS works on all browsers, CSS works only on IE.
	        onready = function() {
	            if (!loaded && (!this.readyState ||
	                    this.readyState === 'loaded' ||
	                    this.readyState === 'complete')) {
	                loaded = true;
	                // 防止内存泄露
	                $(node).unbind('load', onready);
	                $(node).unbind('readystatechange', onready);
	                //node.onload = node.onreadystatechange = null;
	                callback.call(window, node);
	            }
	        };
	        $(node).bind('load', onready);
	        $(node).bind('readystatechange', onready);
	        //CSS has no onload event on firefox and webkit platform, so hack it.
	        if (res.type == 'css') {
	            (function() {
	                //避免重复加载
	                if (loaded) return;
	                try {
	                    node.sheet.cssRule;
	                } catch (e) {
	                    setTimeout(arguments.callee, 20);
	                    return;
	                }
	                loaded = true;
	                callback.call(window, node);
	            })();
	        }

	        node.href = node.src = res.url;
	        document.getElementsByTagName('head')[0].appendChild(node);
	    }

	    //兼容第一个参数直接是资源地址.
	    $.lang.isString(resources) && (resources = [{url: resources}]);
	    //避免递归出错,添加容错.
	    if (! (resources && resources.length)) return;

	    function loadResources(res) {
	        var url = res.url,
	            shouldContinue = !!parallel,
	            cacheData,
	            callback = function(textOrNode) {
	                //ajax存入responseText,dom存入节点,用于保证onload的正确执行.
	                cache[res.url] = textOrNode;
	                delete loadingCache[res.url];

	                if ($.lang.isFunction(res.onload)) {
	                    //若返回false, 则停止接下来的加载.
	                    if (false === res.onload.call(window, textOrNode)) {
	                        return;
	                    }
	                }
	                //串行时递归执行
	                !parallel && self(resources.slice(1), options, true);
	                if ((! ignoreAllLoaded) && $.lang.isFunction(options.onload)) {
	                    allLoadedChecker();
	                }
	            };
	        //默认用后缀名, 并防止后缀名大写
	        res.type = res.type || url.replace(/^[^\?#]+\.(css|js|html)(\?|#| |$)[^\?#]*/i, '$1'); //[bugfix]修改xxx.js?v这种情况下取不到js的问题。 
	        //默认html格式用ajax请求,其他都使用dom标签方式请求.
	        res.requestType = res.requestType || (res.type == 'html' ? 'ajax' : 'dom');

	        if (cacheData = cache[res.url]) {
	            callback(cacheData);
	            return shouldContinue;
	        }
	        if (!options.refresh && loadingCache[res.url]) {
	            setTimeout(function() {loadResources(res);}, 10);
	            return shouldContinue;
	        }
	        loadingCache[res.url] = true;
	        if (res.requestType.toLowerCase() == 'dom') {
	            loadByDom(res, callback);
	        }else {//ajax
	        	$.getScript(res.url, function(responseText){
	        		callback(responseText);
	        	});
	        }
	        //串行模式,通过callback方法执行后续
	        return shouldContinue;
	    };

	    $.each(resources, function(k, item){
	    	loadResources(item);
	    });
	};
	//默认编码设置为UTF8
	$.page.load.charset = 'UTF8';
})(jQuery);

;(function($){
	/**
	 * 判断浏览器类型
	 */
	$.browser = $.browser || {};

	$.browser.ie = /msie (\d+\.\d+)/i.test(navigator.userAgent) ? (document.documentMode || + RegExp['\x241']) : undefined;
	
	$.browser.firefox = /firefox\/(\d+\.\d+)/i.test(navigator.userAgent) ? + RegExp['\x241'] : undefined;

	$.browser.chrome = /chrome\/(\d+\.\d+)/i.test(navigator.userAgent) ? + RegExp['\x241'] : undefined;
	
	//判断是否为gecko内核
	$.browser.isGecko = /gecko/i.test(navigator.userAgent) && !/like gecko/i.test(navigator.userAgent);
	
	//判断是否为webkit内核
	$.browser.isWebkit = /webkit/i.test(navigator.userAgent);
	
	//判断是否严格标准的渲染模式
	$.browser.isStrict = document.compatMode == "CSS1Compat";

	$.browser.opera = /opera(\/| )(\d+(\.\d+)?)(.+?(version\/(\d+(\.\d+)?)))?/i.test(navigator.userAgent) ?  + ( RegExp["\x246"] || RegExp["\x242"] ) : undefined;

	(function(){
		var ua = navigator.userAgent;
		/**
		 * 判断是否为safari浏览器, 支持ipad
		 * @property safari safari版本号
		 * @grammar $.browser.safari
		 */
		$.browser.safari = /(\d+\.\d)?(?:\.\d)?\s+safari\/?(\d+\.\d+)?/i.test(ua) && !/chrome/i.test(ua) ? + (RegExp['\x241'] || RegExp['\x242']) : undefined;
	})();
})(jQuery);


;(function($){
	/**
	 * 判断平台类型和特性的属性
	 */
	$.platform = $.platform || {};

	/**
	 * 判断是否为android平台
	 */
	$.platform.isAndroid = /android/i.test(navigator.userAgent);


	/**
	 * 判断是否为ipad平台
	 */
	$.platform.isIpad = /ipad/i.test(navigator.userAgent);

	/**
	 * 判断是否为iphone平台
	 */
	$.platform.isIphone = /iphone/i.test(navigator.userAgent);


	/**
	 * 判断是否为macintosh平台
	 */
	$.platform.isMacintosh = /macintosh/i.test(navigator.userAgent);



	/**
	 * 判断是否为windows平台
	 */
	$.platform.isWindows = /windows/i.test(navigator.userAgent);



	/**
	 * 判断是否为x11平台
	 */
	$.platform.isX11 = /x11/i.test(navigator.userAgent);
})(jQuery);


;(function($){
	/**
	 * String增强
	 */
	$.string = $.string || {};

	/**
	 * 对目标字符串进行html解码
	 * @grammar $.string.decodeHTML(source)
	 * @param {string} source 目标字符串
	 *             
	 * @returns {string} html解码后的字符串
	 */
	$.string.decodeHTML = function (source) {
		var str = String(source)
					.replace(/"/g,'"')
					.replace(/</g,'<')
					.replace(/>/g,'>')
					.replace(/&/g, "&");
		//处理转义的中文和实体字符
		return str.replace(/&#([\d]+);/g, function(_0, _1){
			return String.fromCharCode(parseInt(_1, 10));
		});
	};

	/**
	 * 对目标字符串进行html编码
	 * @grammar $.string.encodeHTML(source)
	 * @param {string} source 目标字符串
	 * 编码字符有5个:&<>"'
	 *             
	 * @returns {string} html编码后的字符串
	 */
	$.string.encodeHTML = function (source) {
		return String(source)
					.replace(/&/g,'&')
					.replace(/</g,'<')
					.replace(/>/g,'>')
					.replace(/"/g, """)
					.replace(/'/g, "'");
	};

	/**
	 * 去掉字符串中的html标签
	 * @function
	 * @grammar $.string.stripTags(source)
	 * @param {string} source 要处理的字符串.
	 * @return {String}
	 */
	$.string.stripTags = function(source) {
		return String(source || '').replace(/<[^>]+>/g, '');
	};

	/**
	 * 将目标字符串中可能会影响正则表达式构造的字符串进行转义。
	 * @grammar $.string.escapeReg(source)
	 * @param {string} source 目标字符串
	 * @remark
	 * 给以下字符前加上“\”进行转义:.*+?^=!:${}()|[]/\
	 *             
	 * @returns {string} 转义后的字符串
	 */
	$.string.escapeReg = function (source) {
		return String(source)
				.replace(new RegExp("([.*+?^=!:\x24{}()|[\\]\/\\\\])", "g"), '\\\x241');
	};

	/**
	 * 删除目标字符串两端的空白字符
	 * @grammar $.string.trim(source)
	 * @param {string} source 目标字符串
	 * @remark
	 * 不支持删除单侧空白字符
	 *             
	 * @returns {string} 删除两端空白字符后的字符串
	 */

	(function () {
		var trimer = new RegExp("(^[\\s\\t\\xa0\\u3000]+)|([\\u3000\\xa0\\s\\t]+\x24)", "g");
		
		$.string.trim = function (source) {
			return String(source)
					.replace(trimer, "");
		};
	})();
})(jQuery);


;(function($){
	/**
	 * GUID
	 */
	$.lang = $.lang || {};
	/**
	 * 返回一个当前页面的唯一标识字符串。
	 * @grammar $.lang.guid()
	 *             
	 * @returns {String} 当前页面的唯一标识字符串
	 */
	$.lang.guid = function() {
		return "TANGRAM$" + $.lang._counter ++;
	};

	//不直接使用window,可以提高3倍左右性能
	$.lang._counter = $.lang._counter || 1;
	$.guid = $.lang.guid;//设置$.page.guid别名$.guid


	/**
	 * 判断目标参数是否为function或Function实例
	 * @grammar $.lang.isFunction(source)
	 * @param {Any} source 目标参数
	 * @returns {boolean} 类型判断结果
	 */
	$.lang.isFunction = function (source) {
		// chrome下,'function' == typeof /a/ 为true.
		return '[object Function]' == Object.prototype.toString.call(source);
	};

	/**
	 * 判断目标参数是否为Element对象
	 * @grammar $.lang.isElement(source)
	 * @param {Any} source 目标参数
	 * @returns {boolean} 类型判断结果
	 */
	$.lang.isElement = function (source) {
		return !!(source && source.nodeName && source.nodeType == 1);
	};

	/**
	 * 判断目标参数是否Array对象
	 * @grammar $.lang.isArray(source)
	 * @param {Any} source 目标参数   
	 * @returns {boolean} 类型判断结果
	 */
	$.lang.isArray = function (source) {
		return '[object Array]' == Object.prototype.toString.call(source);
	};
})(jQuery);

;(function($){
	/**
	 * Array增强
	 */
	 $.array = $.array || {};

	/**
	 * 查询数组中指定元素的索引位置
	 * @grammar $.array.indexOf(source, match[, fromIndex])
	 * @param {Array} source 需要查询的数组
	 * @param {Any} match 查询项
	 * @param {number} [fromIndex] 查询的起始位索引位置,如果为负数,则从source.length+fromIndex往后开始查找
	 *             
	 * @returns {number} 指定元素的索引位置,查询不到时返回-1
	 */
	$.array.indexOf = function (source, match, fromIndex) {
		var len = source.length,
			iterator = match;
			
		fromIndex = fromIndex | 0;
		if(fromIndex < 0){//小于0
			fromIndex = Math.max(0, len + fromIndex)
		}
		for ( ; fromIndex < len; fromIndex++) {
			if(fromIndex in source && source[fromIndex] === match) {
				return fromIndex;
			}
		}
		
		return -1;
	};

	/**
	 * 判断一个数组中是否包含给定元素
	 * @grammar $.array.contains(source, obj)
	 * @param {Array} source 需要判断的数组.
	 * @param {Any} obj 要查找的元素.
	 * @return {boolean} 判断结果.
	 * @author berg
	 */
	$.array.contains = function(source, obj) {
		return ($.array.indexOf(source, obj) >= 0);
	};

	/**
	 * 清空一个数组
	 * @grammar $.array.empty(source)
	 * @param {Array} source 需要清空的数组.
	 * @author berg
	 */
	$.array.empty = function(source) {
		source.length = 0;
	};

	/**
	 * 从后往前,查询数组中指定元素的索引位置
	 * @grammar $.array.lastIndexOf(source, match)
	 * @param {Array} source 需要查询的数组
	 * @param {Any} match 查询项
	 * @param {number} [fromIndex] 查询的起始位索引位置,如果为负数,则从source.length+fromIndex往前开始查找
	 *             
	 * @returns {number} 指定元素的索引位置,查询不到时返回-1
	 */

	$.array.lastIndexOf = function (source, match, fromIndex) {
		var len = source.length;

		fromIndex = fromIndex | 0;

		if(!fromIndex || fromIndex >= len){
			fromIndex = len - 1;
		}
		if(fromIndex < 0){
			fromIndex += len;
		}
		for(; fromIndex >= 0; fromIndex --){
			if(fromIndex in source && source[fromIndex] === match){
				return fromIndex;
			}
		}
		
		return -1;
	};

	/**
	 * 遍历数组中所有元素,将每一个元素应用方法进行转换,并返回转换后的新数组。
	 * @grammar $.array.map(source, iterator[, thisObject])
	 * @param {Array}    source   需要遍历的数组.
	 * @param {Function} iterator 对每个数组元素进行处理的函数.
	 * @param {Object} [thisObject] 函数调用时的this指针,如果没有此参数,默认是当前遍历的数组
	 * @return {Array} map后的数组.
	 */
	$.array.map = function(source, iterator, thisObject) {
		var results = [],
			i = 0,
			l = source.length;
		for (; i < l; i++) {
			results[i] = iterator.call(thisObject || source, source[i], i);
		}
		return results;
	};

	/**
	 * 遍历数组中所有元素,将每一个元素应用方法进行合并,并返回合并后的结果。
	 * @grammar $.array.reduce(source, iterator[, initializer])
	 * @param {Array}    source 需要遍历的数组.
	 * @param {Function} iterator 对每个数组元素进行处理的函数,函数接受四个参数:上一次reduce的结果(或初始值),当前元素值,索引值,整个数组.
	 * @param {Object}   [initializer] 合并的初始项,如果没有此参数,默认用数组中的第一个值作为初始值.
	 * @return {Array} reduce后的值.
	 */
	$.array.reduce = function(source, iterator, initializer) {
		var i = 0,
			l = source.length,
			found = 0;

		if( arguments.length < 3){
			//没有initializer的情况,找到第一个可用的值
			for(; i < l; i++){
				initializer = source[i++];
				found = 1;
				break;
			}
			if(!found){
				return ;
			}
		}

		for (; i < l; i++) {
			if( i in source){
				initializer = iterator(initializer, source[i] , i , source);
			}
		}
		return initializer;
	};

	/**
	 * 移除数组中的项
	 * @grammar $.array.remove(source, match)
	 * @param {Array} source 需要移除项的数组
	 * @param {Any} match 要移除的项
	 *             
	 * @returns {Array} 移除后的数组
	 */
	$.array.remove = function (source, match) {
		var len = source.length;
			
		while (len--) {
			if (len in source && source[len] === match) {
				source.splice(len, 1);
			}
		}
		return source;
	};

	/**
	 * 移除数组中的项
	 * @grammar $.array.removeAt(source, index)
	 * @param {Array} source 需要移除项的数组
	 * @param {number} index 要移除项的索引位置
	 * @returns {Any} 被移除的数组项
	 */
	$.array.removeAt = function (source, index) {
		return source.splice(index, 1)[0];
	};

	/**
	 * 过滤数组中的相同项。如果两个元素相同,会删除后一个元素。
	 * @grammar $.array.unique(source[, compareFn])
	 * @param {Array} source 需要过滤相同项的数组
	 * @param {Function} [compareFn] 比较两个数组项是否相同的函数,两个数组项作为函数的参数。
	 *             
	 * @returns {Array} 过滤后的新数组
	 */
	$.array.unique = function (source, compareFn) {
		var len = source.length,
			result = source.slice(0),
			i, datum;
			
		if ('function' != typeof compareFn) {
			compareFn = function (item1, item2) {
				return item1 === item2;
			};
		}
		
		// 从后往前双重循环比较
		// 如果两个元素相同,删除后一个
		while (--len > 0) {
			datum = result[len];
			i = len;
			while (i--) {
				if (compareFn(datum, result[i])) {
					result.splice(len, 1);
					break;
				}
			}
		}

		return result;
	};
})(jQuery);

;(function(){
	/**
	 * 操作cookie的方法
	 * @namespace $.cookie
	 */
	$.cookie = $.cookie || {};

	/**
	 * 验证字符串是否合法的cookie键名
	 * 
	 * @param {string} source 需要遍历的数组
	 * @meta standard
	 * @return {boolean} 是否合法的cookie键名
	 */
	$.cookie._isValidKey = function (key) {
		// http://www.w3.org/Protocols/rfc2109/rfc2109
		// Syntax:  General
		// The two state management headers, Set-Cookie and Cookie, have common
		// syntactic properties involving attribute-value pairs.  The following
		// grammar uses the notation, and tokens DIGIT (decimal digits) and
		// token (informally, a sequence of non-special, non-white space
		// characters) from the HTTP/1.1 specification [RFC 2068] to describe
		// their syntax.
		// av-pairs   = av-pair *(";" av-pair)
		// av-pair    = attr ["=" value] ; optional value
		// attr       = token
		// value      = word
		// word       = token | quoted-string
		
		// http://www.ietf.org/rfc/rfc2068.txt
		// token      = 1*<any CHAR except CTLs or tspecials>
		// CHAR       = <any US-ASCII character (octets 0 - 127)>
		// CTL        = <any US-ASCII control character
		//              (octets 0 - 31) and DEL (127)>
		// tspecials  = "(" | ")" | "<" | ">" | "@"
		//              | "," | ";" | ":" | "\" | <">
		//              | "/" | "[" | "]" | "?" | "="
		//              | "{" | "}" | SP | HT
		// SP         = <US-ASCII SP, space (32)>
		// HT         = <US-ASCII HT, horizontal-tab (9)>
			
		return (new RegExp("^[^\\x00-\\x20\\x7f\\(\\)<>@,;:\\\\\\\"\\[\\]\\?=\\{\\}\\/\\u0080-\\uffff]+\x24")).test(key);
	};

	/**
	 * 获取cookie的值,不对值进行解码
	 * @grammar $.cookie.getRaw(key)
	 * @param {string} key 需要获取Cookie的键名
	 * @returns {string|null} 获取的Cookie值,获取不到时返回null
	 */
	$.cookie.getRaw = function (key) {
		if ($.cookie._isValidKey(key)) {
			var reg = new RegExp("(^| )" + key + "=([^;]*)(;|\x24)"),
				result = reg.exec(document.cookie);
				
			if (result) {
				return result[2] || null;
			}
		}

		return null;
	};

	/**
	 * 设置cookie的值,不对值进行编码
	 * @grammar $.cookie.setRaw(key, value[, options])
	 * @param {string} key 需要设置Cookie的键名
	 * @param {string} value 需要设置Cookie的值
	 * @param {Object} [options] 设置Cookie的其他可选参数
	 * @config {string} [path] cookie路径
	 * @config {Date|number} [expires] cookie过期时间,如果类型是数字的话, 单位是毫秒
	 * @config {string} [domain] cookie域名
	 * @config {string} [secure] cookie是否安全传输
	 * @remark
	 * 
	<b>options参数包括:</b><br>
	path:cookie路径<br>
	expires:cookie过期时间,Number型,单位为毫秒。<br>
	domain:cookie域名<br>
	secure:cookie是否安全传输
	 */
	$.cookie.setRaw = function (key, value, options) {
		if (!$.cookie._isValidKey(key)) {
			return;
		}
		
		options = options || {};
		//options.path = options.path || "/"; // meizz 20100402 设定一个初始值,方便后续的操作
		//berg 20100409 去掉,因为用户希望默认的path是当前路径,这样和浏览器对cookie的定义也是一致的
		
		// 计算cookie过期时间
		var expires = options.expires;
		if ('number' == typeof options.expires) {
			expires = new Date();
			expires.setTime(expires.getTime() + options.expires);
		}
		
		document.cookie =
			key + "=" + value
			+ (options.path ? "; path=" + options.path : "")
			+ (expires ? "; expires=" + expires.toGMTString() : "")
			+ (options.domain ? "; domain=" + options.domain : "")
			+ (options.secure ? "; secure" : ''); 
	};

	/**
	 * 删除cookie的值
	 * @grammar $.cookie.remove(key, options)
	 * @param {string} key 需要删除Cookie的键名
	 * @param {Object} options 需要删除的cookie对应的 path domain 等值
	 */
	$.cookie.remove = function (key, options) {
		options = options || {};
		options.expires = new Date(0);
		$.cookie.setRaw(key, '', options);
	};

	/**
	 * 获取cookie的值,用decodeURIComponent进行解码
	 * @grammar $.cookie.get(key)
	 * @param {string} key 需要获取Cookie的键名
	 * @remark
	 * <b>注意:</b>该方法会对cookie值进行decodeURIComponent解码。如果想获得cookie源字符串,请使用getRaw方法。
	 *             
	 * @returns {string|null} cookie的值,获取不到时返回null
	 */
	$.cookie.get = function (key) {
		var value = $.cookie.getRaw(key);
		if ('string' == typeof value) {
			value = decodeURIComponent(value);
			return value;
		}
		return null;
	};

	/**
	 * 设置cookie的值,用encodeURIComponent进行编码
	 * @grammar $.cookie.set(key, value[, options])
	 * @param {string} key 需要设置Cookie的键名
	 * @param {string} value 需要设置Cookie的值
	 * @param {Object} [options] 设置Cookie的其他可选参数
	 * @config {string} [path] cookie路径
	 * @config {Date|number} [expires] cookie过期时间,如果类型是数字的话, 单位是毫秒
	 * @config {string} [domain] cookie域名
	 * @config {string} [secure] cookie是否安全传输
	 * @remark
	 * 
	1. <b>注意:</b>该方法会对cookie值进行encodeURIComponent编码。如果想设置cookie源字符串,请使用setRaw方法。<br><br>
	2. <b>options参数包括:</b><br>
	path:cookie路径<br>
	expires:cookie过期时间,Number型,单位为毫秒。<br>
	domain:cookie域名<br>
	secure:cookie是否安全传输
	 */
	$.cookie.set = function (key, value, options) {
		$.cookie.setRaw(key, encodeURIComponent(value), options);
	};
})(jQuery);

;(function($){
	$.number = $.number || {};

	/**
	 * 为目标数字添加逗号分隔
	 * @grammar $.number.comma(source[, length])
	 * @param {number} source 需要处理的数字
	 * @param {number} [length] 两次逗号之间的数字位数,默认为3位
	 *             
	 * @returns {string} 添加逗号分隔后的字符串
	 */
	$.number.comma = function (source, length) {
		if (!length || length < 1) {
			length = 3;
		}

		source = String(source).split(".");
		source[0] = source[0].replace(new RegExp('(\\d)(?=(\\d{'+length+'})+$)','ig'),"$1,");
		return source.join(".");
	};

	/**
	 * 生成随机整数,范围是[min, max]
	 * @grammar $.number.randomInt(min, max) 
	 * 
	 * @param 	{number} min 	随机整数的最小值
	 * @param 	{number} max 	随机整数的最大值
	 * @return 	{number} 		生成的随机整数
	 */
	$.number.randomInt = function(min, max){
		return Math.floor(Math.random() * (max - min + 1) + min);
	};

	/**
	 * 对目标数字进行0补齐处理
	 * @grammar $.number.pad(source, length)
	 * @param {number} source 需要处理的数字
	 * @param {number} length 需要输出的长度
	 *             
	 * @returns {string} 对目标数字进行0补齐处理后的结果
	 */
	$.number.pad = function (source, length) {
		var pre = "",
			negative = (source < 0),
			string = String(Math.abs(source));

		if (string.length < length) {
			pre = (new Array(length - string.length + 1)).join('0');
		}

		return (negative ?  "-" : "") + pre + string;
	};
})(jQuery);

;(function($){
	$.sio = $.sio || {};
	/**
	 * 通过请求一个图片的方式令服务器存储一条日志
	 * @grammar $.sio.log(url)
	 * @param {string} url 要发送的地址.
	 */
	$.sio.log = function(url) {
	  var img = new Image(),
		  key = 'tangram_sio_log_' + Math.floor(Math.random() *
				2147483648).toString(36);

	  // 这里一定要挂在window下
	  // 在IE中,如果没挂在window下,这个img变量又正好被GC的话,img的请求会abort
	  // 导致服务器收不到日志
	  window[key] = img;

	  img.onload = img.onerror = img.onabort = function() {
		// 下面这句非常重要
		// 如果这个img很不幸正好加载了一个存在的资源,又是个gif动画
		// 则在gif动画播放过程中,img会多次触发onload
		// 因此一定要清空
		img.onload = img.onerror = img.onabort = null;

		window[key] = null;

		// 下面这句非常重要
		// new Image创建的是DOM,DOM的事件中形成闭包环引用DOM是典型的内存泄露
		// 因此这里一定要置为null
		img = null;
	  };

	  // 一定要在注册了事件之后再设置src
	  // 不然如果图片是读缓存的话,会错过事件处理
	  // 最后,对于url最好是添加客户端时间来防止缓存
	  // 同时服务器也配合一下传递Cache-Control: no-cache;
	  img.src = url;
	};
})(jQuery);


;(function($){
	$.url = $.url || {};
	/**
	 * 对字符串进行%#&+=以及和\s匹配的所有字符进行url转义
	 * @grammar $.url.escapeSymbol(source)
	 * @param {string} source 需要转义的字符串.
	 * @return {string} 转义之后的字符串.
	 * @remark
	 * 用于get请求转义。在服务器只接受gbk,并且页面是gbk编码时,可以经过本转义后直接发get请求。
	 *
	 * @return {string} 转义后的字符串
	 */
	$.url.escapeSymbol = function(source) {
		
		//TODO: 之前使用\s来匹配任意空白符
		//发现在ie下无法匹配中文全角空格和纵向指标符\v,所以改\s为\f\r\n\t\v以及中文全角空格和英文空格
		//但是由于ie本身不支持纵向指标符\v,故去掉对其的匹配,保证各浏览器下效果一致
		return String(source).replace(/[#%&+=\/\\\ \ \f\r\n\t]/g, function(all) {
			return '%' + (0x100 + all.charCodeAt()).toString(16).substring(1).toUpperCase();
		});
	};

	/**
	 * 根据参数名从目标URL中获取参数值
	 * @grammar $.url.getQueryValue(url, key)
	 * @param {string} url 目标URL
	 * @param {string} key 要获取的参数名
	 *             
	 * @returns {string|null} - 获取的参数值,其中URI编码后的字符不会被解码,获取不到时返回null
	 */
	$.url.getQueryValue = function (url, key) {
		var reg = new RegExp(
							"(^|&|\\?|#)" 
							+ $.string.escapeReg(key) 
							+ "=([^&#]*)(&|\x24|#)", 
						"");
		var match = url.match(reg);
		if (match) {
			return match[2];
		}
		
		return null;
	};

	/**
	 * 将json对象解析成query字符串
	 * @grammar $.url.jsonToQuery(json[, replacer])
	 * @param {Object} json 需要解析的json对象
	 * @param {Function=} replacer_opt 对值进行特殊处理的函数,function (value, key)
	 *             
	 * @return {string} - 解析结果字符串,其中值将被URI编码,{a:'&1 '} ==> "a=%261%20"。
	 */
	$.url.jsonToQuery = function (json, replacer_opt) {
		var result = [], 
			itemLen,
			replacer = replacer_opt || function (value) {
			  return $.url.escapeSymbol(value);
			};
			
		$.each(json, function(item, key){
			// 这里只考虑item为数组、字符串、数字类型,不考虑嵌套的object
			if ($.lang.isArray(item)) {
				itemLen = item.length;
				// value的值需要encodeURIComponent转义吗?
				// FIXED 优化了escapeSymbol函数
				while (itemLen--) {
					result.push(key + '=' + replacer(item[itemLen], key));
				}
			} else {
				result.push(key + '=' + replacer(item, key));
			}
		});
		
		return result.join('&');
	};


	/**
	 * 解析目标URL中的参数成json对象
	 * @grammar $.url.queryToJson(url)
	 * @param {string} url 目标URL
	 *             
	 * @returns {Object} - 解析为结果对象,其中URI编码后的字符不会被解码,'a=%20' ==> {a:'%20'}。
	 */
	$.url.queryToJson = function (url) {
		var query   = url.substr(url.lastIndexOf('?') + 1),
			params  = query.split('&'),
			len     = params.length,
			result  = {},
			i       = 0,
			key, value, item, param;
		
		for (; i < len; i++) {
			if(!params[i]){
				continue;
			}
			param   = params[i].split('=');
			key     = param[0];
			value   = param[1];
			
			item = result[key];
			if ('undefined' == typeof item) {
				result[key] = value;
			} else if ($.lang.isArray(item)) {
				item.push(value);
			} else { // 这里只可能是string了
				result[key] = [item, value];
			}
		}
		
		return result;
	};
})(jQuery);


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值