/**
* Author: shiddong
*/
/**
* 扩展字符串的方法:翻转字符串
* @param
* str: 需要翻转的字符串
*
* @description
* 数组有reverse方法,先将字符串分隔成数组,翻转之后再拼接
*/
function reverse(str) {
return str.split('').reverse().join('');
}
/**
* 检查属性是否是在原型中
* @param
* obj: 检查的对象
* attr: 检查的属性
*
* @description
* hasOwnProperty()方法检查对象实例中的属性,in操作符会两个都检查(实例和原型中)
* 即:hasOwnProperty()只在属性存在于实例中才返回true,而in操作符只要通过对象能够访问到属性就返回true
*/
function hasPrototyeProperty(obj, attr) {
return !obj.hasOwnProperty(attr) && (attr in obj);
}
/**
* 动态加载 JavaScript 脚本
*
* @param
* url: JavaScript 文件的 URL
* callback: 当 JavaScript 接收完成时触发的回调函数
*
* @description
* 1.Firefox、Opera, Chorme 和 Safari 3+会在<script>节点接收完成之后发出一个 onload 事件。您可以监听这一事件,以得到脚本准备好的通知。
* 2.Internet Explorer 支持另一种实现方式,它发出一个 readystatechange 事件。<script>元素有一个 readyState 属性,它的值随着下载外部文件的过程而改变。readyState 有五种取值:
* "uninitialized":默认状态
* "loading":下载开始
* "loaded":下载完成
* "interactive":下载完成但尚不可用
* "complete":所有数据已经准备好
*
* 微软文档上说,在<script>元素的生命周期中,readyState 的这些取值不一定全部出现,但并没有指出哪些取值总会被用到。实践中,我们最感兴趣的是“loaded”和“complete”状态。
* Internet Explorer 对这两个 readyState 值所表示的最终状态并不一致,有时<script>元素会得到“loader”却从不出现“complete”,但另外一些情况下出现“complete”而用不到“loaded”。
* 最安全的办法就是在 readystatechange 事件中检查这两种状态,并且当其中一种状态出现时,删除 readystatechange 事件句柄(保证事件不会被处理两次)。
*
* @示例:
* loadScript("script.js", function(){
* alert("File is loaded!");
* });
*
* 可以在页面中动态加载很多 JavaScript 文件,但要注意,浏览器不保证文件加载的顺序。所有主流浏览器之中,只有 Firefox 和 Opera 保证脚本按照你指定的顺序执行。
* 其他浏览器将按照服务器返回它们的次序下载并运行不同的代码文件。
*
* 我们可以将下载操作串联在一起以保证他们的次序:
* loadScript("script1.js", function(){
* loadScript("script2.js", function(){
* loadScript("script3.js", function(){
* alert("All files are loaded!");
* });
* });
* });
* 如果多个文件的次序十分重要,更好的办法是将这些文件按照正确的次序连接成一个文件。独立文件可以一次性下载所有代码(由于这是异步进行的,使用一个大文件并没有什么损失)。
*/
function loadScript(url, callback) {
var script = document.createElement("script")
script.type = "text/javascript";
if (script.readyState) { //IE
script.onreadystatechange = function () {
if (script.readyState == "loaded" || script.readyState == "complete") {
script.onreadystatechange = null; // 删除 readystatechange 事件句柄
callback();
}
};
} else { //Others
script.onload = function () {
callback();
};
}
script.src = url;
document.getElementsByTagName("head")[0].appendChild(script);
}
/**
* JSONP 网页动态插入<script>元素的另一种写法
* @description
* 网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;
* 服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
*
* 由于<script>元素请求的脚本,直接作为代码运行。这时,只要浏览器定义了callbackFn函数,该函数就会立即调用。
* 作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤
*/
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
function callbackFn(data) {
console.log('Your public IP address is: ' + data.ip);
};
window.onload = function () {
addScriptTag('http://example.com/ip?callback=callbackFn');
}
/**
* 休眠
*
* @param
* milliSeconds: {ms} 休眠时间毫秒
*
* @description
* javascript 中不存在自带的 sleep 方法,要想休眠需要自己定义
*/
function sleep(milliSeconds) {
var startTime = new Date().getTime();
while (new Date().getTime() < startTime + milliSeconds);
}
/**
* 判断是否为质数
*
* @param {Number} element
* @returns {Boolean}
*/
function isPrime(element) {
var start = 2;
while (start <= Math.sqrt(element)) {
if (element % start++ < 1) {
return false;
}
}
return element > 1;
}
/**
* Angular 中判断安全地执行 apply() /digest() 方法
* @description
* 也可以使用 $$phase 进行判断 —— $$phase是 angluar 内部使用的状态标志位,用于标识当前是否处于 digest 状态。
* if(!$rootScope.$$phase) {
* $scope.apply();
* }
*
* @param {Function} 回调函数
*
*/
function safeApply (fn){
var phase = this.$root.$$phase;
if (phase == '$apply' || phase == '$digest') {
// 或者用 Object.prototype.toString.call(value) == "[object Function]" 判断,或者 angular.isFunction(fn) 进行判断
fn && (typeof fn === 'function') && fn();
} else {
this.$apply(fn);
}
}
/**
* 判断是否是中文
*
* @others
* 需要匹配所有中日韩非符号字符,那么正则表达式应该是^[/u3400-/u9FFF]+$
*
* 这里是几个主要非英文语系字符范围(google上找到的):
* 2E80~33FFh:中日韩符号区。收容康熙字典部首、中日韩辅助部首、注音符号、日本假名、韩文音符,中日韩的符号、标点、带圈或带括符文数字、月份,以及日本的假名组合、单位、年号、月份、日期、时间等。
* 3400~4DFFh:中日韩认同表意文字扩充A区,总计收容6,582个中日韩汉字。
* 4E00~9FFFh:中日韩认同表意文字区,总计收容20,902个中日韩汉字。
* A000~A4FFh:彝族文字区,收容中国南方彝族文字和字根。
* AC00~D7FFh:韩文拼音组合字区,收容以韩文音符拼成的文字。
* F900~FAFFh:中日韩兼容表意文字区,总计收容302个中日韩汉字。
* FB00~FFFDh:文字表现形式区,收容组合拉丁文字、希伯来文、阿拉伯文、中日韩直式标点、小符号、半角符号、全角符号等。
*/
function isChinese (text) {
return /^[\u4e00-\u9fa5]+$/.test(text);
}
/**
* 判断对象是否非空
*
* 这是jQuery中的实现
*/
function isEmptyObject(obj) {
var prop;
for (prop in obj) { // 可以结合 obj.hasOwnProperty(prop)来判断对象本身是否包含这个属性
return false;
}
return true;
}
/**
* Object.keys 的 Polyfill
*
* @Desc
* hasDontEnumBug:这是针对老式的IE浏览器会存在对对象属性遍历的bug,当我们在实例对象中实现原型中不可遍历的属性时,
* IE会忽略,还是认为它不可遍历。
* @others
* in:prop in obj
* 左操作数是属性名或者数组索引,其他的包括属性的值都会返回false
* 右操作数必须是一个对象值,可以是一个String包装对象,但不能是一个字符串原始值
*/
if (!Object.keys) {
Object.keys = (function () {
var hasOwnProperty = Object.prototype.hasOwnProperty,
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), // 在一个对象实例上添加一个原型上的属性,判断是否可遍历,来判断浏览器是否存在实现的bug
dontEnums = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'constructor' ],
dontEnumsLength = dontEnums.length;
return function (obj) {
if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object');
var result = [];
for (var prop in obj) { // 可见,Object.keys 还是以 in 来实现的,in在所有的浏览器中都支持
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
if (hasDontEnumBug) { // 当存在enumerable的bug时,就需要对对象的原型属性一一判断是否存在于实例本身,hasOwnProperty方法可以做到
for (var i=0; i < dontEnumsLength; i++) {
if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]);
}
}
return result;
};
})();
};
/**
* 封装 设置缓存 和 获取缓存 的方式
*
* @descriptor
* localstorage是Html5中新加入的特性,引入localstorage主要是作为浏览器本地存储,解决cookie作为存储容量不足的问题。
* localstorage是一种持久化的存储。同样,localstorage也是一个key-value形式的存储。
* (一)浏览器提供了localstorage的增删改查方法
* 增加/修改:window.localStorage.setItem("username","admin");
* 查询: window.localStorage.getItem("username");
* 删除: window.localStorage.removeItem("username","admin");
* (二)使用localstorage的注意事项
* localstorage中存储的value只能是字符串型,如果要存储对象,需要转换为字符串再进行保存。
*
* @other
* Storage类型: sessionStorage localStorage(取代 globalStorage) IndexedDB(取代 Web SQL) Cookie
* 注:在较高版本的浏览器中,js提供了sessionStorage和globalStorage。在Html5中提供了localStorage来取代globalStorage。
* html5中的Web Storage包括了两种存储方式:sessionStorage和localStorage。
* sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。
* 因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。 而localStorage用于持久化的本地存储,除非主动删除数据,否则数据是永远不会过期的。
*/
function setLocalStorage(name, value) {
var cache = {
data: value,
preTime: new Date().getTime()
};
localStorage.setItem(name, JSON.stringify(cache));
};
function getLocalStorage(name, overtime) {
var cache = localStorage.getItem(name);
if (cache && cache !== 'undefined') {
cacheObj = JSON.parse(cache);
var now = new Date().getTime();
if (cacheObj && cacheObj.preTime && now - cacheObj.preTime < overtime) {
return cacheObj.data;
}
}
return null;
}
// 判断是否为IE浏览器
function isIEBrowser () {
var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串
var isOpera = userAgent.indexOf("Opera") > -1; //判断是否Opera浏览器
if (userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1 && !isOpera) {
return true;
}
return false;
}
/**
* 获取 IE 的版本
* IE 11 changed the format of the UserAgent string.
* See http://msdn.microsoft.com/en-us/library/ms537503.aspx
*/
function int(str) {
return parseInt(str, 10);
}
var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;};
msie = int((/msie (\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
if (isNaN(msie)) {
msie = int((/trident\/.*; rv:(\d+)/.exec(lowercase(navigator.userAgent)) || [])[1]);
}
function isString(value){return typeof value === 'string';}
/**
* @private
* @param {*} obj
* @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments,
* String ...)
*/
function isArrayLike(obj) {
if (obj == null || isWindow(obj)) {
return false;
}
var length = obj.length;
if (obj.nodeType === 1 && length) {
return true;
}
return isString(obj) || isArray(obj) || length === 0 ||
typeof length === 'number' && length > 0 && (length - 1) in obj;
}
/**
* 操作 Cookie 的工具方法实现
*/
var CookieUtil = {
get: function (name){
var cookieName = encodeURIComponent(name) + "=",
cookieStart = document.cookie.indexOf(cookieName),
cookieValue = null,
cookieEnd;
if (cookieStart > -1){
cookieEnd = document.cookie.indexOf(";", cookieStart);
if (cookieEnd == -1){
cookieEnd = document.cookie.length;
}
cookieValue = decodeURIComponent(document.cookie.substring(cookieStart + cookieName.length, cookieEnd));
}
return cookieValue;
},
set: function (name, value, expires, path, domain, secure) {
var cookieText = encodeURIComponent(name) + "=" + encodeURIComponent(value);
if (expires instanceof Date) {
cookieText += "; expires=" + expires.toGMTString();
}
if (path) {
cookieText += "; path=" + path;
}
if (domain) {
cookieText += "; domain=" + domain;
}
if (secure) {
cookieText += "; secure";
}
document.cookie = cookieText;
},
unset: function (name, path, domain, secure){
this.set(name, "", new Date(0), path, domain, secure);
}
};
/**
* @name getPreMonth
* @desc 获取前 prev 个月的日期表示(解决跨年计算问题)
* // 等价于 date = date.setMonth( date.getMonth() + prev ) 正负数皆可,更加方便
*
* @author shiddong
* @param {Number} prev
* @param {Date} dateIn
* @param {Boolean} computerTime 是否用计算机时间表示(月份是从 0 开始表示, 人类时间是从 1 开始)
*
* @return {Object {Number}}
*
*/
function getPreMonth(prev, dateIn, computerTime) {
// dateIn 默认为当前年月份
var tips = 'Please input a correct number. the interface is like: [getPreMonth(prev, dateIn, humanTime)].'
if (prev < 0) throw (tips);
var date = dateIn ? new Date(dateIn) : new Date(),
year = date.getFullYear(),
month = date.getMonth() + 1; // 默认从 0-11 开始, 转化为 1-12 便于处理
var preYear = parseInt(prev / 12),
preMonth = prev % 12;
var reYear, reMonth; // 计算的返回值
if (preMonth >= month) {
reMonth = month - preMonth + 12;
reYear = year - preYear - 1;
} else {
reMonth = month - preMonth;
reYear = year - preYear;
}
if (computerTime) {
--reMonth;
}
return {
year: reYear,
month: reMonth
}
}
/**
* 来自 Angular 1.2.19 源码
***********************************************************************************/
/**
* @ngdoc function
* @name angular.isUndefined
* @module ng
* @kind function
*
* @description
* Determines if a reference is undefined.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is undefined.
*/
function isUndefined(value){return typeof value === 'undefined';}
/**
* @ngdoc function
* @name angular.isDefined
* @module ng
* @kind function
*
* @description
* Determines if a reference is defined.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is defined.
*/
function isDefined(value){return typeof value !== 'undefined';}
/**
* @ngdoc function
* @name angular.isObject
* @module ng
* @kind function
*
* @description
* Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
* considered to be objects. Note that JavaScript arrays are objects.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Object` but not `null`.
*/
function isObject(value){return value != null && typeof value === 'object';}
/**
* @ngdoc function
* @name angular.isString
* @module ng
* @kind function
*
* @description
* Determines if a reference is a `String`.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `String`.
*/
function isString(value){return typeof value === 'string';}
/**
* @ngdoc function
* @name angular.isNumber
* @module ng
* @kind function
*
* @description
* Determines if a reference is a `Number`.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Number`.
*/
function isNumber(value){return typeof value === 'number';}
/**
* @ngdoc function
* @name angular.isDate
* @module ng
* @kind function
*
* @description
* Determines if a value is a date.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Date`.
*/
function isDate(value) {
return toString.call(value) === '[object Date]';
}
/**
* @ngdoc function
* @name angular.isArray
* @module ng
* @kind function
*
* @description
* Determines if a reference is an `Array`.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is an `Array`.
*/
var isArray = (function() {
if (!isFunction(Array.isArray)) {
return function(value) {
return toString.call(value) === '[object Array]';
};
}
return Array.isArray;
})();
/**
* @ngdoc function
* @name angular.isFunction
* @module ng
* @kind function
*
* @description
* Determines if a reference is a `Function`.
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `Function`.
*/
function isFunction(value){return typeof value === 'function';}
/**
* Determines if a value is a regular expression object.
*
* @private
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a `RegExp`.
*/
function isRegExp(value) {
return toString.call(value) === '[object RegExp]';
}
/**
* Checks if `obj` is a window object.
*
* @private
* @param {*} obj Object to check
* @returns {boolean} True if `obj` is a window obj.
*/
function isWindow(obj) {
return obj && obj.document && obj.location && obj.alert && obj.setInterval;
}
function isScope(obj) {
return obj && obj.$evalAsync && obj.$watch;
}
function isFile(obj) {
return toString.call(obj) === '[object File]';
}
function isBlob(obj) {
return toString.call(obj) === '[object Blob]';
}
function isBoolean(value) {
return typeof value === 'boolean';
}
var trim = (function() {
// native trim is way faster: http://jsperf.com/angular-trim-test
// but IE doesn't have it... :-(
// TODO: we should move this into IE/ES5 polyfill
if (!String.prototype.trim) {
return function(value) {
return isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
};
}
return function(value) {
return isString(value) ? value.trim() : value;
};
})();
/**
* @ngdoc function
* @name angular.isElement
* @module ng
* @kind function
*
* @description
* Determines if a reference is a DOM element (or wrapped jQuery element).
*
* @param {*} value Reference to check.
* @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
*/
function isElement(node) {
return !!(node &&
(node.nodeName // we are a direct element
|| (node.prop && node.attr && node.find))); // we have an on and find method part of jQuery API
}