easy-player-pro 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,686 @@
1
+ // winlin.utility.js
2
+
3
+ /**
4
+ * common utilities
5
+ * depends: jquery1.10
6
+ * https://gitee.com/winlinvip/codes/rpn0c2ewbomj81augzk4y59
7
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
8
+ * v 1.0.23
9
+ */
10
+
11
+ /**
12
+ * padding the output.
13
+ * padding(3, 5, '0') is 00003
14
+ * padding(3, 5, 'x') is xxxx3
15
+ * @see http://blog.csdn.net/win_lin/article/details/12065413
16
+ */
17
+ function padding(number, length, prefix) {
18
+ if(String(number).length >= length){
19
+ return String(number);
20
+ }
21
+ return padding(prefix+number, length, prefix);
22
+ }
23
+
24
+ /**
25
+ * extends system array, to remove all specified elem.
26
+ * @param arr the array to remove elem from.
27
+ * @param elem the elem to remove.
28
+ * @remark all elem will be removed.
29
+ * for example,
30
+ * arr = [10, 15, 20, 30, 20, 40]
31
+ * system_array_remove(arr, 10) // arr=[15, 20, 30, 20, 40]
32
+ * system_array_remove(arr, 20) // arr=[15, 30, 40]
33
+ */
34
+ function system_array_remove(arr, elem) {
35
+ if (!arr) {
36
+ return;
37
+ }
38
+
39
+ var removed = true;
40
+ var i = 0;
41
+ while (removed) {
42
+ removed = false;
43
+ for (; i < arr.length; i++) {
44
+ if (elem == arr[i]) {
45
+ arr.splice(i, 1);
46
+ removed = true;
47
+ break;
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ /**
54
+ * whether the array contains specified element.
55
+ * @param arr the array to find.
56
+ * @param elem_or_function the element value or compare function.
57
+ * @returns true contains elem; otherwise false.
58
+ * for example,
59
+ * arr = [10, 15, 20, 30, 20, 40]
60
+ * system_array_contains(arr, 10) // true
61
+ * system_array_contains(arr, 11) // false
62
+ * system_array_contains(arr, function(elem){return elem == 30;}); // true
63
+ * system_array_contains(arr, function(elem){return elem == 60;}); // false
64
+ */
65
+ function system_array_contains(arr, elem_or_function) {
66
+ return system_array_get(arr, elem_or_function) != null;
67
+ }
68
+
69
+ /**
70
+ * get the specified element from array
71
+ * @param arr the array to find.
72
+ * @param elem_or_function the element value or compare function.
73
+ * @returns the matched elem; otherwise null.
74
+ * for example,
75
+ * arr = [10, 15, 20, 30, 20, 40]
76
+ * system_array_get(arr, 10) // 10
77
+ * system_array_get(arr, 11) // null
78
+ * system_array_get(arr, function(elem){return elem == 30;}); // 30
79
+ * system_array_get(arr, function(elem){return elem == 60;}); // null
80
+ */
81
+ function system_array_get(arr, elem_or_function) {
82
+ for (var i = 0; i < arr.length; i++) {
83
+ if (typeof elem_or_function == "function") {
84
+ if (elem_or_function(arr[i])) {
85
+ return arr[i];
86
+ }
87
+ } else {
88
+ if (elem_or_function == arr[i]) {
89
+ return arr[i];
90
+ }
91
+ }
92
+ }
93
+ return null;
94
+ }
95
+
96
+ /**
97
+ * to iterate on array.
98
+ * @param arr the array to iterate on.
99
+ * @param pfn the function to apply on it. return false to break loop.
100
+ * for example,
101
+ * arr = [10, 15, 20, 30, 20, 40]
102
+ * system_array_foreach(arr, function(elem, index){
103
+ * console.log('index=' + index + ',elem=' + elem);
104
+ * });
105
+ * @return true when iterate all elems.
106
+ */
107
+ function system_array_foreach(arr, pfn) {
108
+ if (!pfn) {
109
+ return false;
110
+ }
111
+
112
+ for (var i = 0; i < arr.length; i++) {
113
+ if (!pfn(arr[i], i)) {
114
+ return false;
115
+ }
116
+ }
117
+
118
+ return true;
119
+ }
120
+
121
+ /**
122
+ * whether the str starts with flag.
123
+ */
124
+ function system_string_startswith(str, flag) {
125
+ if (typeof flag == "object" && flag.constructor == Array) {
126
+ for (var i = 0; i < flag.length; i++) {
127
+ if (system_string_startswith(str, flag[i])) {
128
+ return true;
129
+ }
130
+ }
131
+ }
132
+
133
+ return str && flag && str.length >= flag.length && str.indexOf(flag) == 0;
134
+ }
135
+
136
+ /**
137
+ * whether the str ends with flag.
138
+ */
139
+ function system_string_endswith(str, flag) {
140
+ if (typeof flag == "object" && flag.constructor == Array) {
141
+ for (var i = 0; i < flag.length; i++) {
142
+ if (system_string_endswith(str, flag[i])) {
143
+ return true;
144
+ }
145
+ }
146
+ }
147
+
148
+ return str && flag && str.length >= flag.length && str.indexOf(flag) == str.length - flag.length;
149
+ }
150
+
151
+ /**
152
+ * trim the start and end of flag in str.
153
+ * @param flag a string to trim.
154
+ */
155
+ function system_string_trim(str, flag) {
156
+ if (!flag || !flag.length || typeof flag != "string") {
157
+ return str;
158
+ }
159
+
160
+ while (system_string_startswith(str, flag)) {
161
+ str = str.slice(flag.length);
162
+ }
163
+
164
+ while (system_string_endswith(str, flag)) {
165
+ str = str.slice(0, str.length - flag.length);
166
+ }
167
+
168
+ return str;
169
+ }
170
+
171
+ /**
172
+ * array sort asc, for example:
173
+ * [a, b] in [10, 11, 9]
174
+ * then sort to: [9, 10, 11]
175
+ * Usage, for example:
176
+ obj.data.data.sort(function(a, b){
177
+ return array_sort_asc(a.metadata.meta_id, b.metadata.meta_id);
178
+ });
179
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
180
+ * @remark, if need desc, use -1*array_sort_asc(a,b)
181
+ */
182
+ function array_sort_asc(elem_a, elem_b) {
183
+ if (elem_a > elem_b) {
184
+ return 1;
185
+ }
186
+ return (elem_a < elem_b)? -1 : 0;
187
+ }
188
+ function array_sort_desc(elem_a, elem_b) {
189
+ return -1 * array_sort_asc(elem_a, elem_b);
190
+ }
191
+ function system_array_sort_asc(elem_a, elem_b) {
192
+ return array_sort_asc(elem_a, elem_b);
193
+ }
194
+ function system_array_sort_desc(elem_a, elem_b) {
195
+ return -1 * array_sort_asc(elem_a, elem_b);
196
+ }
197
+
198
+ /**
199
+ * parse the query string to object.
200
+ * parse the url location object as: host(hostname:http_port), pathname(dir/filename)
201
+ * for example, url http://192.168.1.168:1980/ui/players.html?vhost=player.vhost.com&app=test&stream=livestream
202
+ * parsed to object:
203
+ {
204
+ host : "192.168.1.168:1980",
205
+ hostname : "192.168.1.168",
206
+ http_port : 1980,
207
+ pathname : "/ui/players.html",
208
+ dir : "/ui",
209
+ filename : "/players.html",
210
+
211
+ vhost : "player.vhost.com",
212
+ app : "test",
213
+ stream : "livestream"
214
+ }
215
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
216
+ */
217
+ function parse_query_string(){
218
+ var obj = {};
219
+
220
+ // add the uri object.
221
+ // parse the host(hostname:http_port), pathname(dir/filename)
222
+ obj.host = window.location.host;
223
+ obj.hostname = window.location.hostname;
224
+ obj.http_port = (window.location.port == "")? 80:window.location.port;
225
+ obj.pathname = window.location.pathname;
226
+ if (obj.pathname.lastIndexOf("/") <= 0) {
227
+ obj.dir = "/";
228
+ obj.filename = "";
229
+ } else {
230
+ obj.dir = obj.pathname.slice(0, obj.pathname.lastIndexOf("/"));
231
+ obj.filename = obj.pathname.slice(obj.pathname.lastIndexOf("/"));
232
+ }
233
+
234
+ // pure user query object.
235
+ obj.user_query = {};
236
+
237
+ // parse the query string.
238
+ var query_string = String(window.location.search).replace(" ", "").split("?")[1];
239
+ if(query_string === undefined){
240
+ query_string = String(window.location.hash).replace(" ", "").split("#")[1];
241
+ if(query_string === undefined){
242
+ return obj;
243
+ }
244
+ }
245
+
246
+ __fill_query(query_string, obj);
247
+
248
+ return obj;
249
+ }
250
+
251
+ function __fill_query(query_string, obj) {
252
+ // pure user query object.
253
+ obj.user_query = {};
254
+
255
+ if (query_string.length === 0) {
256
+ return;
257
+ }
258
+
259
+ // split again for angularjs.
260
+ if (query_string.indexOf("?") >= 0) {
261
+ query_string = query_string.split("?")[1];
262
+ }
263
+
264
+ var queries = query_string.split("&");
265
+ for (var i = 0; i < queries.length; i++) {
266
+ var elem = queries[i];
267
+
268
+ var query = elem.split("=");
269
+ obj[query[0]] = query[1];
270
+ obj.user_query[query[0]] = query[1];
271
+ }
272
+
273
+ // alias domain for vhost.
274
+ if (obj.domain) {
275
+ obj.vhost = obj.domain;
276
+ }
277
+ }
278
+
279
+ /**
280
+ * parse the rtmp url,
281
+ * for example: rtmp://demo.srs.com:1935/live...vhost...players/livestream
282
+ * @return object {server, port, vhost, app, stream}
283
+ * for exmaple, rtmp_url is rtmp://demo.srs.com:1935/live...vhost...players/livestream
284
+ * parsed to object:
285
+ {
286
+ server: "demo.srs.com",
287
+ port: 1935,
288
+ vhost: "players",
289
+ app: "live",
290
+ stream: "livestream"
291
+ }
292
+ */
293
+ function parse_rtmp_url(rtmp_url) {
294
+ // @see: http://stackoverflow.com/questions/10469575/how-to-use-location-object-to-parse-url-without-redirecting-the-page-in-javascri
295
+ var a = document.createElement("a");
296
+ a.href = rtmp_url.replace("rtmp://", "http://")
297
+ .replace("webrtc://", "http://")
298
+ .replace("rtc://", "http://");
299
+
300
+ var vhost = a.hostname;
301
+ var app = a.pathname.substring(1, a.pathname.lastIndexOf("/"));
302
+ var stream = a.pathname.slice(a.pathname.lastIndexOf("/") + 1);
303
+
304
+ // parse the vhost in the params of app, that srs supports.
305
+ app = app.replace("...vhost...", "?vhost=");
306
+ if (app.indexOf("?") >= 0) {
307
+ var params = app.slice(app.indexOf("?"));
308
+ app = app.slice(0, app.indexOf("?"));
309
+
310
+ if (params.indexOf("vhost=") > 0) {
311
+ vhost = params.slice(params.indexOf("vhost=") + "vhost=".length);
312
+ if (vhost.indexOf("&") > 0) {
313
+ vhost = vhost.slice(0, vhost.indexOf("&"));
314
+ }
315
+ }
316
+ }
317
+
318
+ // when vhost equals to server, and server is ip,
319
+ // the vhost is __defaultVhost__
320
+ if (a.hostname === vhost) {
321
+ var re = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/;
322
+ if (re.test(a.hostname)) {
323
+ vhost = "__defaultVhost__";
324
+ }
325
+ }
326
+
327
+ // parse the schema
328
+ var schema = "rtmp";
329
+ if (rtmp_url.indexOf("://") > 0) {
330
+ schema = rtmp_url.slice(0, rtmp_url.indexOf("://"));
331
+ }
332
+
333
+ var port = a.port;
334
+ if (!port) {
335
+ if (schema === 'http') {
336
+ port = 80;
337
+ } else if (schema === 'https') {
338
+ port = 443;
339
+ } else if (schema === 'rtmp') {
340
+ port = 1935;
341
+ }
342
+ }
343
+
344
+ var ret = {
345
+ url: rtmp_url,
346
+ schema: schema,
347
+ server: a.hostname, port: port,
348
+ vhost: vhost, app: app, stream: stream
349
+ };
350
+ __fill_query(a.search, ret);
351
+
352
+ // For webrtc API, we use 443 if page is https, or schema specified it.
353
+ if (!ret.port) {
354
+ if (schema === 'webrtc' || schema === 'rtc') {
355
+ if (ret.user_query.schema === 'https') {
356
+ ret.port = 443;
357
+ } else if (window.location.href.indexOf('https://') === 0) {
358
+ ret.port = 443;
359
+ } else {
360
+ // For WebRTC, SRS use 1985 as default API port.
361
+ ret.port = 1985;
362
+ }
363
+ }
364
+ }
365
+
366
+ return ret;
367
+ }
368
+
369
+ /**
370
+ * get the agent.
371
+ * @return an object specifies some browser.
372
+ * for example, get_browser_agents().MSIE
373
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
374
+ */
375
+ function get_browser_agents() {
376
+ var agent = navigator.userAgent;
377
+
378
+ /**
379
+ WindowsPC platform, Win7:
380
+ chrome 31.0.1650.63:
381
+ Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
382
+ (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
383
+ firefox 23.0.1:
384
+ Mozilla/5.0 (Windows NT 6.1; WOW64; rv:23.0) Gecko/20100101
385
+ Firefox/23.0
386
+ safari 5.1.7(7534.57.2):
387
+ Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/534.57.2
388
+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2
389
+ opera 15.0.1147.153:
390
+ Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36
391
+ (KHTML, like Gecko) Chrome/28.0.1500.95 Safari/537.36
392
+ OPR/15.0.1147.153
393
+ 360 6.2.1.272:
394
+ Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
395
+ Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
396
+ .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
397
+ .NET4.0E)
398
+ IE 10.0.9200.16750(update: 10.0.12):
399
+ Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64;
400
+ Trident/6.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729;
401
+ .NET CLR 3.0.30729; Media Center PC 6.0; InfoPath.2; .NET4.0C;
402
+ .NET4.0E)
403
+ */
404
+
405
+ return {
406
+ // platform
407
+ Android: agent.indexOf("Android") != -1,
408
+ Windows: agent.indexOf("Windows") != -1,
409
+ iPhone: agent.indexOf("iPhone") != -1,
410
+ // Windows Browsers
411
+ Chrome: agent.indexOf("Chrome") != -1,
412
+ Firefox: agent.indexOf("Firefox") != -1,
413
+ QQBrowser: agent.indexOf("QQBrowser") != -1,
414
+ MSIE: agent.indexOf("MSIE") != -1,
415
+ // Android Browsers
416
+ Opera: agent.indexOf("Presto") != -1,
417
+ MQQBrowser: agent.indexOf("MQQBrowser") != -1
418
+ };
419
+ }
420
+
421
+ /**
422
+ * format relative seconds to HH:MM:SS,
423
+ * for example, 210s formated to 00:03:30
424
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
425
+ * @usage relative_seconds_to_HHMMSS(210)
426
+ */
427
+ function relative_seconds_to_HHMMSS(seconds){
428
+ var date = new Date();
429
+ date.setTime(Number(seconds) * 1000);
430
+
431
+ var ret = padding(date.getUTCHours(), 2, '0')
432
+ + ":" + padding(date.getUTCMinutes(), 2, '0')
433
+ + ":" + padding(date.getUTCSeconds(), 2, '0');
434
+
435
+ return ret;
436
+ }
437
+
438
+ /**
439
+ * format absolute seconds to HH:MM:SS,
440
+ * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 10:01:20
441
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
442
+ * @usage absolute_seconds_to_HHMMSS(new Date().getTime() / 1000)
443
+ */
444
+ function absolute_seconds_to_HHMMSS(seconds){
445
+ var date = new Date();
446
+ date.setTime(Number(seconds) * 1000);
447
+
448
+ var ret = padding(date.getHours(), 2, '0')
449
+ + ":" + padding(date.getMinutes(), 2, '0')
450
+ + ":" + padding(date.getSeconds(), 2, '0');
451
+
452
+ return ret;
453
+ }
454
+
455
+ /**
456
+ * format absolute seconds to YYYY-mm-dd,
457
+ * for example, 1389146480s (2014-01-08 10:01:20 GMT+0800) formated to 2014-01-08
458
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
459
+ * @usage absolute_seconds_to_YYYYmmdd(new Date().getTime() / 1000)
460
+ */
461
+ function absolute_seconds_to_YYYYmmdd(seconds) {
462
+ var date = new Date();
463
+ date.setTime(Number(seconds) * 1000);
464
+
465
+ var ret = date.getFullYear()
466
+ + "-" + padding(date.getMonth() + 1, 2, '0')
467
+ + "-" + padding(date.getDate(), 2, '0');
468
+
469
+ return ret;
470
+ }
471
+
472
+ /**
473
+ * parse the date in str to Date object.
474
+ * @param str the date in str, format as "YYYY-mm-dd", for example, 2014-12-11
475
+ * @returns a date object.
476
+ * @usage YYYYmmdd_parse("2014-12-11")
477
+ */
478
+ function YYYYmmdd_parse(str) {
479
+ var date = new Date();
480
+ date.setTime(Date.parse(str));
481
+ return date;
482
+ }
483
+
484
+ /**
485
+ * async refresh function call. to avoid multiple call.
486
+ * @remark AsyncRefresh is for jquery to refresh the speicified pfn in a page;
487
+ * if angularjs, use AsyncRefresh2 to change pfn, cancel previous request for angularjs use singleton object.
488
+ * @param refresh_interval the default refresh interval ms.
489
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
490
+ * the pfn can be implements as following:
491
+ var async_refresh = new AsyncRefresh(pfn, 3000);
492
+ function pfn() {
493
+ if (!async_refresh.refresh_is_enabled()) {
494
+ async_refresh.request(100);
495
+ return;
496
+ }
497
+ $.ajax({
498
+ type: 'GET', async: true, url: 'xxxxx',
499
+ complete: function(){
500
+ if (!async_refresh.refresh_is_enabled()) {
501
+ async_refresh.request(0);
502
+ } else {
503
+ async_refresh.request(async_refresh.refresh_interval);
504
+ }
505
+ },
506
+ success: function(res){
507
+ // if donot allow refresh, directly return.
508
+ if (!async_refresh.refresh_is_enabled()) {
509
+ return;
510
+ }
511
+
512
+ // render the res.
513
+ }
514
+ });
515
+ }
516
+ */
517
+ function AsyncRefresh(pfn, refresh_interval) {
518
+ this.refresh_interval = refresh_interval;
519
+
520
+ this.__handler = null;
521
+ this.__pfn = pfn;
522
+
523
+ this.__enabled = true;
524
+ }
525
+ /**
526
+ * disable the refresher, the pfn must check the refresh state.
527
+ */
528
+ AsyncRefresh.prototype.refresh_disable = function() {
529
+ this.__enabled = false;
530
+ }
531
+ AsyncRefresh.prototype.refresh_enable = function() {
532
+ this.__enabled = true;
533
+ }
534
+ AsyncRefresh.prototype.refresh_is_enabled = function() {
535
+ return this.__enabled;
536
+ }
537
+ /**
538
+ * start new async request
539
+ * @param timeout the timeout in ms.
540
+ * user can use the refresh_interval of the AsyncRefresh object,
541
+ * which initialized in constructor.
542
+ */
543
+ AsyncRefresh.prototype.request = function(timeout) {
544
+ if (this.__handler) {
545
+ clearTimeout(this.__handler);
546
+ }
547
+
548
+ this.__handler = setTimeout(this.__pfn, timeout);
549
+ }
550
+
551
+ /**
552
+ * async refresh v2, support cancellable refresh, and change the refresh pfn.
553
+ * @remakr for angularjs. if user only need jquery, maybe AsyncRefresh is better.
554
+ * @see: http://blog.csdn.net/win_lin/article/details/17994347
555
+ * Usage:
556
+ bsmControllers.controller('CServers', ['$scope', 'MServer', function($scope, MServer){
557
+ async_refresh2.refresh_change(function(){
558
+ // 获取服务器列表
559
+ MServer.servers_load({}, function(data){
560
+ $scope.servers = data.data.servers;
561
+ async_refresh2.request();
562
+ });
563
+ }, 3000);
564
+
565
+ async_refresh2.request(0);
566
+ }]);
567
+ bsmControllers.controller('CStreams', ['$scope', 'MStream', function($scope, MStream){
568
+ async_refresh2.refresh_change(function(){
569
+ // 获取流列表
570
+ MStream.streams_load({}, function(data){
571
+ $scope.streams = data.data.streams;
572
+ async_refresh2.request();
573
+ });
574
+ }, 3000);
575
+
576
+ async_refresh2.request(0);
577
+ }]);
578
+ */
579
+ function AsyncRefresh2() {
580
+ /**
581
+ * the function callback before call the pfn.
582
+ * the protype is function():bool, which return true to invoke, false to abort the call.
583
+ * null to ignore this callback.
584
+ *
585
+ * for example, user can abort the refresh by find the class popover:
586
+ * async_refresh2.on_before_call_pfn = function() {
587
+ * if ($(".popover").length > 0) {
588
+ * async_refresh2.request();
589
+ * return false;
590
+ * }
591
+ * return true;
592
+ * };
593
+ */
594
+ this.on_before_call_pfn = null;
595
+
596
+ // use a anonymous function to call, and check the enabled when actually invoke.
597
+ this.__call = {
598
+ pfn: null,
599
+ timeout: 0,
600
+ __enabled: false,
601
+ __handler: null
602
+ };
603
+ }
604
+ // singleton
605
+ var async_refresh2 = new AsyncRefresh2();
606
+ /**
607
+ * initialize or refresh change. cancel previous request, setup new request.
608
+ * @param pfn a function():void to request after timeout. null to disable refresher.
609
+ * @param timeout the timeout in ms, to call pfn. null to disable refresher.
610
+ */
611
+ AsyncRefresh2.prototype.initialize = function(pfn, timeout) {
612
+ this.refresh_change(pfn, timeout);
613
+ }
614
+ /**
615
+ * stop refresh, the refresh pfn is set to null.
616
+ */
617
+ AsyncRefresh2.prototype.stop = function() {
618
+ this.__call.__enabled = false;
619
+ }
620
+ /**
621
+ * restart refresh, use previous config.
622
+ */
623
+ AsyncRefresh2.prototype.restart = function() {
624
+ this.__call.__enabled = true;
625
+ this.request(0);
626
+ }
627
+ /**
628
+ * change refresh pfn, the old pfn will set to disabled.
629
+ */
630
+ AsyncRefresh2.prototype.refresh_change = function(pfn, timeout) {
631
+ // cancel the previous call.
632
+ if (this.__call.__handler) {
633
+ clearTimeout(this.__handler);
634
+ }
635
+ this.__call.__enabled = false;
636
+
637
+ // setup new call.
638
+ this.__call = {
639
+ pfn: pfn,
640
+ timeout: timeout,
641
+ __enabled: true,
642
+ __handler: null
643
+ };
644
+ }
645
+ /**
646
+ * start new request, we never auto start the request,
647
+ * user must start new request when previous completed.
648
+ * @param timeout [optional] if not specified, use the timeout in initialize or refresh_change.
649
+ */
650
+ AsyncRefresh2.prototype.request = function(timeout) {
651
+ var self = this;
652
+ var this_call = this.__call;
653
+
654
+ // clear previous timeout.
655
+ if (this_call.__handler) {
656
+ clearTimeout(this_call.__handler);
657
+ }
658
+
659
+ // override the timeout
660
+ if (timeout == undefined) {
661
+ timeout = this_call.timeout;
662
+ }
663
+
664
+ // if user disabled refresher.
665
+ if (this_call.pfn == null || timeout == null) {
666
+ return;
667
+ }
668
+
669
+ this_call.__handler = setTimeout(function(){
670
+ // cancelled by refresh_change, ignore.
671
+ if (!this_call.__enabled) {
672
+ return;
673
+ }
674
+
675
+ // callback if the handler installled.
676
+ if (self.on_before_call_pfn) {
677
+ if (!self.on_before_call_pfn()) {
678
+ return;
679
+ }
680
+ }
681
+
682
+ // do the actual call.
683
+ this_call.pfn();
684
+ }, timeout);
685
+ }
686
+