687 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			687 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | // winlin.utility.js
 | ||
|  | 
 | ||
|  | /** | ||
|  |  * common utilities | ||
|  |  * depends: jquery1.10 | ||
|  |  * https://gitee.com/winlinvip/codes/rpn0c2ewbomj81augzk4y59
 | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  * v 1.0.23 | ||
|  |  */ | ||
|  | 
 | ||
|  | /** | ||
|  |  * padding the output. | ||
|  |  * padding(3, 5, '0') is 00003 | ||
|  |  * padding(3, 5, 'x') is xxxx3 | ||
|  |  * @see http://blog.csdn.net/win_lin/article/details/12065413
 | ||
|  |  */ | ||
|  | function padding(number, length, prefix) { | ||
|  |     if(String(number).length >= length){ | ||
|  |         return String(number); | ||
|  |     } | ||
|  |     return padding(prefix+number, length, prefix); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * extends system array, to remove all specified elem. | ||
|  |  * @param arr the array to remove elem from. | ||
|  |  * @param elem the elem to remove. | ||
|  |  * @remark all elem will be removed. | ||
|  |  * for example, | ||
|  |  *      arr = [10, 15, 20, 30, 20, 40] | ||
|  |  *      system_array_remove(arr, 10) // arr=[15, 20, 30, 20, 40]
 | ||
|  |  *      system_array_remove(arr, 20) // arr=[15, 30, 40]
 | ||
|  |  */ | ||
|  | function system_array_remove(arr, elem) { | ||
|  |     if (!arr) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     var removed = true; | ||
|  |     var i = 0; | ||
|  |     while (removed) { | ||
|  |         removed = false; | ||
|  |         for (; i < arr.length; i++) { | ||
|  |             if (elem == arr[i]) { | ||
|  |                 arr.splice(i, 1); | ||
|  |                 removed = true; | ||
|  |                 break; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * whether the array contains specified element. | ||
|  |  * @param arr the array to find. | ||
|  |  * @param elem_or_function the element value or compare function. | ||
|  |  * @returns true contains elem; otherwise false. | ||
|  |  * for example, | ||
|  |  *      arr = [10, 15, 20, 30, 20, 40] | ||
|  |  *      system_array_contains(arr, 10) // true
 | ||
|  |  *      system_array_contains(arr, 11) // false
 | ||
|  |  *      system_array_contains(arr, function(elem){return elem == 30;}); // true
 | ||
|  |  *      system_array_contains(arr, function(elem){return elem == 60;}); // false
 | ||
|  |  */ | ||
|  | function system_array_contains(arr, elem_or_function) { | ||
|  |     return system_array_get(arr, elem_or_function) != null; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * get the specified element from array | ||
|  |  * @param arr the array to find. | ||
|  |  * @param elem_or_function the element value or compare function. | ||
|  |  * @returns the matched elem; otherwise null. | ||
|  |  * for example, | ||
|  |  *      arr = [10, 15, 20, 30, 20, 40] | ||
|  |  *      system_array_get(arr, 10) // 10
 | ||
|  |  *      system_array_get(arr, 11) // null
 | ||
|  |  *      system_array_get(arr, function(elem){return elem == 30;}); // 30
 | ||
|  |  *      system_array_get(arr, function(elem){return elem == 60;}); // null
 | ||
|  |  */ | ||
|  | function system_array_get(arr, elem_or_function) { | ||
|  |     for (var i = 0; i < arr.length; i++) { | ||
|  |         if (typeof elem_or_function == "function") { | ||
|  |             if (elem_or_function(arr[i])) { | ||
|  |                 return arr[i]; | ||
|  |             } | ||
|  |         } else { | ||
|  |             if (elem_or_function == arr[i]) { | ||
|  |                 return arr[i]; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |     return null; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * to iterate on array. | ||
|  |  * @param arr the array to iterate on. | ||
|  |  * @param pfn the function to apply on it. return false to break loop. | ||
|  |  * for example, | ||
|  |  *      arr = [10, 15, 20, 30, 20, 40] | ||
|  |  *      system_array_foreach(arr, function(elem, index){ | ||
|  |  *          console.log('index=' + index + ',elem=' + elem); | ||
|  |  *      }); | ||
|  |  * @return true when iterate all elems. | ||
|  |  */ | ||
|  | function system_array_foreach(arr, pfn) { | ||
|  |     if (!pfn) { | ||
|  |         return false; | ||
|  |     } | ||
|  | 
 | ||
|  |     for (var i = 0; i < arr.length; i++) { | ||
|  |         if (!pfn(arr[i], i)) { | ||
|  |             return false; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return true; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * whether the str starts with flag. | ||
|  |  */ | ||
|  | function system_string_startswith(str, flag) { | ||
|  |     if (typeof flag == "object" && flag.constructor == Array) { | ||
|  |         for (var i = 0; i < flag.length; i++) { | ||
|  |             if (system_string_startswith(str, flag[i])) { | ||
|  |                 return true; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return str && flag && str.length >= flag.length && str.indexOf(flag) == 0; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * whether the str ends with flag. | ||
|  |  */ | ||
|  | function system_string_endswith(str, flag) { | ||
|  |     if (typeof flag == "object" && flag.constructor == Array) { | ||
|  |         for (var i = 0; i < flag.length; i++) { | ||
|  |             if (system_string_endswith(str, flag[i])) { | ||
|  |                 return true; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return str && flag && str.length >= flag.length && str.indexOf(flag) == str.length - flag.length; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * trim the start and end of flag in str. | ||
|  |  * @param flag a string to trim. | ||
|  |  */ | ||
|  | function system_string_trim(str, flag) { | ||
|  |     if (!flag || !flag.length || typeof flag != "string") { | ||
|  |         return str; | ||
|  |     } | ||
|  | 
 | ||
|  |     while (system_string_startswith(str, flag)) { | ||
|  |         str = str.slice(flag.length); | ||
|  |     } | ||
|  | 
 | ||
|  |     while (system_string_endswith(str, flag)) { | ||
|  |         str = str.slice(0, str.length - flag.length); | ||
|  |     } | ||
|  | 
 | ||
|  |     return str; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * array sort asc, for example: | ||
|  |  * [a, b] in [10, 11, 9] | ||
|  |  * then sort to: [9, 10, 11] | ||
|  |  * Usage, for example: | ||
|  |  obj.data.data.sort(function(a, b){ | ||
|  |             return array_sort_asc(a.metadata.meta_id, b.metadata.meta_id); | ||
|  |         }); | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  * @remark, if need desc, use -1*array_sort_asc(a,b) | ||
|  |  */ | ||
|  | function array_sort_asc(elem_a, elem_b) { | ||
|  |     if (elem_a > elem_b) { | ||
|  |         return 1; | ||
|  |     } | ||
|  |     return (elem_a < elem_b)? -1 : 0; | ||
|  | } | ||
|  | function array_sort_desc(elem_a, elem_b) { | ||
|  |     return -1 * array_sort_asc(elem_a, elem_b); | ||
|  | } | ||
|  | function system_array_sort_asc(elem_a, elem_b) { | ||
|  |     return array_sort_asc(elem_a, elem_b); | ||
|  | } | ||
|  | function system_array_sort_desc(elem_a, elem_b) { | ||
|  |     return -1 * array_sort_asc(elem_a, elem_b); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * parse the query string to object. | ||
|  |  * parse the url location object as: host(hostname:http_port), pathname(dir/filename) | ||
|  |  * for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream
 | ||
|  |  * parsed to object: | ||
|  |  { | ||
|  |      host        : "192.168.1.168:1980", | ||
|  |      hostname    : "192.168.1.168", | ||
|  |      http_port   : 1980, | ||
|  |      pathname    : "/ui/players.html", | ||
|  |      dir         : "/ui", | ||
|  |      filename    : "/players.html", | ||
|  | 
 | ||
|  |      vhost       : "player.vhost.com", | ||
|  |      app         : "test", | ||
|  |      stream      : "livestream" | ||
|  |  } | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  */ | ||
|  | function parse_query_string(){ | ||
|  |     var obj = {}; | ||
|  | 
 | ||
|  |     // add the uri object.
 | ||
|  |     // parse the host(hostname:http_port), pathname(dir/filename)
 | ||
|  |     obj.host = window.location.host; | ||
|  |     obj.hostname = window.location.hostname; | ||
|  |     obj.http_port = (window.location.port == "")? 80:window.location.port; | ||
|  |     obj.pathname = window.location.pathname; | ||
|  |     if (obj.pathname.lastIndexOf("/") <= 0) { | ||
|  |         obj.dir = "/"; | ||
|  |         obj.filename = ""; | ||
|  |     } else { | ||
|  |         obj.dir = obj.pathname.slice(0, obj.pathname.lastIndexOf("/")); | ||
|  |         obj.filename = obj.pathname.slice(obj.pathname.lastIndexOf("/")); | ||
|  |     } | ||
|  | 
 | ||
|  |     // pure user query object.
 | ||
|  |     obj.user_query = {}; | ||
|  | 
 | ||
|  |     // parse the query string.
 | ||
|  |     var query_string = String(window.location.search).replace(" ", "").split("?")[1]; | ||
|  |     if(query_string === undefined){ | ||
|  |         query_string = String(window.location.hash).replace(" ", "").split("#")[1]; | ||
|  |         if(query_string === undefined){ | ||
|  |             return obj; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     __fill_query(query_string, obj); | ||
|  | 
 | ||
|  |     return obj; | ||
|  | } | ||
|  | 
 | ||
|  | function __fill_query(query_string, obj) { | ||
|  |     // pure user query object.
 | ||
|  |     obj.user_query = {}; | ||
|  | 
 | ||
|  |     if (query_string.length === 0) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     // split again for angularjs.
 | ||
|  |     if (query_string.indexOf("?") >= 0) { | ||
|  |         query_string = query_string.split("?")[1]; | ||
|  |     } | ||
|  | 
 | ||
|  |     var queries = query_string.split("&"); | ||
|  |     for (var i = 0; i < queries.length; i++) { | ||
|  |         var elem = queries[i]; | ||
|  | 
 | ||
|  |         var query = elem.split("="); | ||
|  |         obj[query[0]] = query[1]; | ||
|  |         obj.user_query[query[0]] = query[1]; | ||
|  |     } | ||
|  | 
 | ||
|  |     // alias domain for vhost.
 | ||
|  |     if (obj.domain) { | ||
|  |         obj.vhost = obj.domain; | ||
|  |     } | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * parse the rtmp url, | ||
|  |  * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
 | ||
|  |  * @return object {server, port, vhost, app, stream} | ||
|  |  * for exmaple, rtmp_url is rtmp://demo.srs.com:1935/live...vhost...players/livestream
 | ||
|  |  * parsed to object: | ||
|  |  { | ||
|  |     server: "demo.srs.com", | ||
|  |     port: 1935, | ||
|  |     vhost: "players", | ||
|  |     app: "live", | ||
|  |     stream: "livestream" | ||
|  |  } | ||
|  |  */ | ||
|  | function parse_rtmp_url(rtmp_url) { | ||
|  |     // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
 | ||
|  |     var a = document.createElement("a"); | ||
|  |     a.href = rtmp_url.replace("rtmp://", "http://") | ||
|  |         .replace("webrtc://", "http://") | ||
|  |         .replace("rtc://", "http://"); | ||
|  | 
 | ||
|  |     var vhost = a.hostname; | ||
|  |     var app = a.pathname.substring(1, a.pathname.lastIndexOf("/")); | ||
|  |     var stream = a.pathname.slice(a.pathname.lastIndexOf("/") + 1); | ||
|  | 
 | ||
|  |     // parse the vhost in the params of app, that srs supports.
 | ||
|  |     app = app.replace("...vhost...", "?vhost="); | ||
|  |     if (app.indexOf("?") >= 0) { | ||
|  |         var params = app.slice(app.indexOf("?")); | ||
|  |         app = app.slice(0, app.indexOf("?")); | ||
|  | 
 | ||
|  |         if (params.indexOf("vhost=") > 0) { | ||
|  |             vhost = params.slice(params.indexOf("vhost=") + "vhost=".length); | ||
|  |             if (vhost.indexOf("&") > 0) { | ||
|  |                 vhost = vhost.slice(0, vhost.indexOf("&")); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     // when vhost equals to server, and server is ip,
 | ||
|  |     // the vhost is __defaultVhost__
 | ||
|  |     if (a.hostname === vhost) { | ||
|  |         var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/; | ||
|  |         if (re.test(a.hostname)) { | ||
|  |             vhost = "__defaultVhost__"; | ||
|  |         } | ||
|  |     } | ||
|  |      | ||
|  |     // parse the schema
 | ||
|  |     var schema = "rtmp"; | ||
|  |     if (rtmp_url.indexOf("://") > 0) { | ||
|  |         schema = rtmp_url.slice(0, rtmp_url.indexOf("://")); | ||
|  |     } | ||
|  | 
 | ||
|  |     var port = a.port; | ||
|  |     if (!port) { | ||
|  |         if (schema === 'http') { | ||
|  |             port = 80; | ||
|  |         } else if (schema === 'https') { | ||
|  |             port = 443; | ||
|  |         } else if (schema === 'rtmp') { | ||
|  |             port = 1935; | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     var ret = { | ||
|  |         url: rtmp_url, | ||
|  |         schema: schema, | ||
|  |         server: a.hostname, port: port, | ||
|  |         vhost: vhost, app: app, stream: stream | ||
|  |     }; | ||
|  |     __fill_query(a.search, ret); | ||
|  | 
 | ||
|  |     // For webrtc API, we use 443 if page is https, or schema specified it.
 | ||
|  |     if (!ret.port) { | ||
|  |         if (schema === 'webrtc' || schema === 'rtc') { | ||
|  |             if (ret.user_query.schema === 'https') { | ||
|  |                 ret.port = 443; | ||
|  |             } else if (window.location.href.indexOf('https://') === 0) { | ||
|  |                 ret.port = 443; | ||
|  |             } else { | ||
|  |                 // For WebRTC, SRS use 1985 as default API port.
 | ||
|  |                 ret.port = 1985; | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  | 
 | ||
|  |     return ret; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * get the agent. | ||
|  |  * @return an object specifies some browser. | ||
|  |  *   for example, get_browser_agents().MSIE | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  */ | ||
|  | function get_browser_agents() { | ||
|  |     var agent = navigator.userAgent; | ||
|  | 
 | ||
|  |     /** | ||
|  |      WindowsPC platform, Win7: | ||
|  |      chrome 31.0.1650.63: | ||
|  |      Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 | ||
|  |      (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 | ||
|  |      firefox 23.0.1: | ||
|  |      Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101 | ||
|  |      Firefox/23.0 | ||
|  |      safari 5.1.7(7534.57.2): | ||
|  |      Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2 | ||
|  |      (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2 | ||
|  |      opera 15.0.1147.153: | ||
|  |      Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 | ||
|  |      (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36 | ||
|  |      OPR/15.0.1147.153 | ||
|  |      360 6.2.1.272: | ||
|  |      Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; | ||
|  |      Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; | ||
|  |      .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; | ||
|  |      .NET4.0E) | ||
|  |      IE 10.0.9200.16750(update: 10.0.12): | ||
|  |      Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; | ||
|  |      Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; | ||
|  |      .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C; | ||
|  |      .NET4.0E) | ||
|  |      */ | ||
|  | 
 | ||
|  |     return { | ||
|  |         // platform
 | ||
|  |         Android: agent.indexOf("Android") != -1, | ||
|  |         Windows: agent.indexOf("Windows") != -1, | ||
|  |         iPhone: agent.indexOf("iPhone") != -1, | ||
|  |         // Windows Browsers
 | ||
|  |         Chrome: agent.indexOf("Chrome") != -1, | ||
|  |         Firefox: agent.indexOf("Firefox") != -1, | ||
|  |         QQBrowser: agent.indexOf("QQBrowser") != -1, | ||
|  |         MSIE: agent.indexOf("MSIE") != -1, | ||
|  |         // Android Browsers
 | ||
|  |         Opera: agent.indexOf("Presto") != -1, | ||
|  |         MQQBrowser: agent.indexOf("MQQBrowser") != -1 | ||
|  |     }; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * format relative seconds to HH:MM:SS, | ||
|  |  * for example, 210s formated to 00:03:30 | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  * @usage relative_seconds_to_HHMMSS(210) | ||
|  |  */ | ||
|  | function relative_seconds_to_HHMMSS(seconds){ | ||
|  |     var date = new Date(); | ||
|  |     date.setTime(Number(seconds) * 1000); | ||
|  | 
 | ||
|  |     var ret = padding(date.getUTCHours(), 2, '0') | ||
|  |         + ":" + padding(date.getUTCMinutes(), 2, '0') | ||
|  |         + ":" + padding(date.getUTCSeconds(), 2, '0'); | ||
|  | 
 | ||
|  |     return ret; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * format absolute seconds to HH:MM:SS, | ||
|  |  * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 10:01:20 | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  * @usage absolute_seconds_to_HHMMSS(new Date().getTime() / 1000) | ||
|  |  */ | ||
|  | function absolute_seconds_to_HHMMSS(seconds){ | ||
|  |     var date = new Date(); | ||
|  |     date.setTime(Number(seconds) * 1000); | ||
|  | 
 | ||
|  |     var ret = padding(date.getHours(), 2, '0') | ||
|  |         + ":" + padding(date.getMinutes(), 2, '0') | ||
|  |         + ":" + padding(date.getSeconds(), 2, '0'); | ||
|  | 
 | ||
|  |     return ret; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * format absolute seconds to YYYY-mm-dd, | ||
|  |  * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 2014-01-08 | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  * @usage absolute_seconds_to_YYYYmmdd(new Date().getTime() / 1000) | ||
|  |  */ | ||
|  | function absolute_seconds_to_YYYYmmdd(seconds) { | ||
|  |     var date = new Date(); | ||
|  |     date.setTime(Number(seconds) * 1000); | ||
|  | 
 | ||
|  |     var ret = date.getFullYear() | ||
|  |         + "-" + padding(date.getMonth() + 1, 2, '0') | ||
|  |         + "-" + padding(date.getDate(), 2, '0'); | ||
|  | 
 | ||
|  |     return ret; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * parse the date in str to Date object. | ||
|  |  * @param str the date in str, format as "YYYY-mm-dd", for example, 2014-12-11 | ||
|  |  * @returns a date object. | ||
|  |  * @usage YYYYmmdd_parse("2014-12-11") | ||
|  |  */ | ||
|  | function YYYYmmdd_parse(str) { | ||
|  |     var date = new Date(); | ||
|  |     date.setTime(Date.parse(str)); | ||
|  |     return date; | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * async refresh function call. to avoid multiple call. | ||
|  |  * @remark AsyncRefresh is for jquery to refresh the speicified pfn in a page; | ||
|  |  *      if angularjs, use AsyncRefresh2 to change pfn, cancel previous request for angularjs use singleton object. | ||
|  |  * @param refresh_interval the default refresh interval ms. | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  * the pfn can be implements as following: | ||
|  |  var async_refresh = new AsyncRefresh(pfn, 3000); | ||
|  |  function pfn() { | ||
|  |             if (!async_refresh.refresh_is_enabled()) { | ||
|  |                 async_refresh.request(100); | ||
|  |                 return; | ||
|  |             } | ||
|  |             $.ajax({ | ||
|  |                 type: 'GET', async: true, url: 'xxxxx', | ||
|  |                 complete: function(){ | ||
|  |                     if (!async_refresh.refresh_is_enabled()) { | ||
|  |                         async_refresh.request(0); | ||
|  |                     } else { | ||
|  |                         async_refresh.request(async_refresh.refresh_interval); | ||
|  |                     } | ||
|  |                 }, | ||
|  |                 success: function(res){ | ||
|  |                     // if donot allow refresh, directly return.
 | ||
|  |                     if (!async_refresh.refresh_is_enabled()) { | ||
|  |                         return; | ||
|  |                     } | ||
|  | 
 | ||
|  |                     // render the res.
 | ||
|  |                 } | ||
|  |             }); | ||
|  |         } | ||
|  |  */ | ||
|  | function AsyncRefresh(pfn, refresh_interval) { | ||
|  |     this.refresh_interval = refresh_interval; | ||
|  | 
 | ||
|  |     this.__handler = null; | ||
|  |     this.__pfn = pfn; | ||
|  | 
 | ||
|  |     this.__enabled = true; | ||
|  | } | ||
|  | /** | ||
|  |  * disable the refresher, the pfn must check the refresh state. | ||
|  |  */ | ||
|  | AsyncRefresh.prototype.refresh_disable = function() { | ||
|  |     this.__enabled = false; | ||
|  | } | ||
|  | AsyncRefresh.prototype.refresh_enable = function() { | ||
|  |     this.__enabled = true; | ||
|  | } | ||
|  | AsyncRefresh.prototype.refresh_is_enabled = function() { | ||
|  |     return this.__enabled; | ||
|  | } | ||
|  | /** | ||
|  |  * start new async request | ||
|  |  * @param timeout the timeout in ms. | ||
|  |  *      user can use the refresh_interval of the AsyncRefresh object, | ||
|  |  *      which initialized in constructor. | ||
|  |  */ | ||
|  | AsyncRefresh.prototype.request = function(timeout) { | ||
|  |     if (this.__handler) { | ||
|  |         clearTimeout(this.__handler); | ||
|  |     } | ||
|  | 
 | ||
|  |     this.__handler = setTimeout(this.__pfn, timeout); | ||
|  | } | ||
|  | 
 | ||
|  | /** | ||
|  |  * async refresh v2, support cancellable refresh, and change the refresh pfn. | ||
|  |  * @remakr for angularjs. if user only need jquery, maybe AsyncRefresh is better. | ||
|  |  * @see: http://blog.csdn.net/win_lin/article/details/17994347
 | ||
|  |  * Usage: | ||
|  |  bsmControllers.controller('CServers', ['$scope', 'MServer', function($scope, MServer){ | ||
|  |             async_refresh2.refresh_change(function(){ | ||
|  |                 // 获取服务器列表
 | ||
|  |                 MServer.servers_load({}, function(data){ | ||
|  |                     $scope.servers = data.data.servers; | ||
|  |                     async_refresh2.request(); | ||
|  |                 }); | ||
|  |             }, 3000); | ||
|  | 
 | ||
|  |             async_refresh2.request(0); | ||
|  |         }]); | ||
|  |  bsmControllers.controller('CStreams', ['$scope', 'MStream', function($scope, MStream){ | ||
|  |             async_refresh2.refresh_change(function(){ | ||
|  |                 // 获取流列表
 | ||
|  |                 MStream.streams_load({}, function(data){ | ||
|  |                     $scope.streams = data.data.streams; | ||
|  |                     async_refresh2.request(); | ||
|  |                 }); | ||
|  |             }, 3000); | ||
|  | 
 | ||
|  |             async_refresh2.request(0); | ||
|  |         }]); | ||
|  |  */ | ||
|  | function AsyncRefresh2() { | ||
|  |     /** | ||
|  |      * the function callback before call the pfn. | ||
|  |      * the protype is function():bool, which return true to invoke, false to abort the call. | ||
|  |      * null to ignore this callback. | ||
|  |      * | ||
|  |      * for example, user can abort the refresh by find the class popover: | ||
|  |      *      async_refresh2.on_before_call_pfn = function() { | ||
|  |      *          if ($(".popover").length > 0) { | ||
|  |      *              async_refresh2.request(); | ||
|  |      *              return false; | ||
|  |      *          } | ||
|  |      *          return true; | ||
|  |      *      }; | ||
|  |      */ | ||
|  |     this.on_before_call_pfn = null; | ||
|  | 
 | ||
|  |     // use a anonymous function to call, and check the enabled when actually invoke.
 | ||
|  |     this.__call = { | ||
|  |         pfn: null, | ||
|  |         timeout: 0, | ||
|  |         __enabled: false, | ||
|  |         __handler: null | ||
|  |     }; | ||
|  | } | ||
|  | // singleton
 | ||
|  | var async_refresh2 = new AsyncRefresh2(); | ||
|  | /** | ||
|  |  * initialize or refresh change. cancel previous request, setup new request. | ||
|  |  * @param pfn a function():void to request after timeout. null to disable refresher. | ||
|  |  * @param timeout the timeout in ms, to call pfn. null to disable refresher. | ||
|  |  */ | ||
|  | AsyncRefresh2.prototype.initialize = function(pfn, timeout) { | ||
|  |     this.refresh_change(pfn, timeout); | ||
|  | } | ||
|  | /** | ||
|  |  * stop refresh, the refresh pfn is set to null. | ||
|  |  */ | ||
|  | AsyncRefresh2.prototype.stop = function() { | ||
|  |     this.__call.__enabled = false; | ||
|  | } | ||
|  | /** | ||
|  |  * restart refresh, use previous config. | ||
|  |  */ | ||
|  | AsyncRefresh2.prototype.restart = function() { | ||
|  |     this.__call.__enabled = true; | ||
|  |     this.request(0); | ||
|  | } | ||
|  | /** | ||
|  |  * change refresh pfn, the old pfn will set to disabled. | ||
|  |  */ | ||
|  | AsyncRefresh2.prototype.refresh_change = function(pfn, timeout) { | ||
|  |     // cancel the previous call.
 | ||
|  |     if (this.__call.__handler) { | ||
|  |         clearTimeout(this.__handler); | ||
|  |     } | ||
|  |     this.__call.__enabled = false; | ||
|  | 
 | ||
|  |     // setup new call.
 | ||
|  |     this.__call = { | ||
|  |         pfn: pfn, | ||
|  |         timeout: timeout, | ||
|  |         __enabled: true, | ||
|  |         __handler: null | ||
|  |     }; | ||
|  | } | ||
|  | /** | ||
|  |  * start new request, we never auto start the request, | ||
|  |  * user must start new request when previous completed. | ||
|  |  * @param timeout [optional] if not specified, use the timeout in initialize or refresh_change. | ||
|  |  */ | ||
|  | AsyncRefresh2.prototype.request = function(timeout) { | ||
|  |     var self = this; | ||
|  |     var this_call = this.__call; | ||
|  | 
 | ||
|  |     // clear previous timeout.
 | ||
|  |     if (this_call.__handler) { | ||
|  |         clearTimeout(this_call.__handler); | ||
|  |     } | ||
|  | 
 | ||
|  |     // override the timeout
 | ||
|  |     if (timeout == undefined) { | ||
|  |         timeout = this_call.timeout; | ||
|  |     } | ||
|  | 
 | ||
|  |     // if user disabled refresher.
 | ||
|  |     if (this_call.pfn == null || timeout == null) { | ||
|  |         return; | ||
|  |     } | ||
|  | 
 | ||
|  |     this_call.__handler = setTimeout(function(){ | ||
|  |         // cancelled by refresh_change, ignore.
 | ||
|  |         if (!this_call.__enabled) { | ||
|  |             return; | ||
|  |         } | ||
|  | 
 | ||
|  |         // callback if the handler installled.
 | ||
|  |         if (self.on_before_call_pfn) { | ||
|  |             if (!self.on_before_call_pfn()) { | ||
|  |                 return; | ||
|  |             } | ||
|  |         } | ||
|  | 
 | ||
|  |         // do the actual call.
 | ||
|  |         this_call.pfn(); | ||
|  |     }, timeout); | ||
|  | } | ||
|  | 
 |