123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685 |
- // 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.22
- */
- /**
- * 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 {
- ret.port = 80;
- }
- }
- }
- 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);
- }
|