├── README.txt ├── content ├── api.html ├── automatic_control.html ├── complex_alternation.html ├── dynamic_callback.html ├── dynamic_timeout.html ├── dynamic_url.html ├── failures_handling.html ├── http_cache.html ├── overview.html ├── remote_callback.html ├── remote_timeout.html ├── smart_stop.html ├── smart_updating.html └── stop_restart.html ├── img ├── close.png ├── close_hover.png ├── close_pushed.png ├── clown.gif ├── collapse-expand.jpg ├── collapse-expand2.jpg ├── collapse-expand3.gif ├── collapse.png ├── demo-spindown-closed.gif ├── demo-spindown-open.gif ├── expand.png └── expand2.png ├── index.html ├── jquery.1.5.0.js ├── main.css ├── main.js ├── php ├── automatic_control.php ├── getmin.php ├── getmin_cache_control.php ├── getmin_cache_etag.php ├── getsec.php ├── getsec_bar.php ├── getsec_foo.php ├── getsecreverse.php ├── gettimestamp.php ├── remote_callback.php └── remote_timeout.php └── smartupdater.js /README.txt: -------------------------------------------------------------------------------- 1 | The only file you need to download and use in your project is 2 | 3 | smartupdater.js 4 | 5 | The rest stuff is demo, which you can see and play with at 6 | http://www.eslinstructor.net/smartupdater3/ 7 | 8 | /** 9 | * smartupdater - jQuery Plugin 10 | * 11 | * Version - 4.0 12 | * Copyright (c) 2010 - 2012 Vadim Kiryukhin 13 | * vkiryukhin @ gmail.com 14 | * 15 | * http://www.eslinstructor.net/smartupdater/ 16 | * 17 | * Dual licensed under the MIT and GPL licenses: 18 | * http://www.opensource.org/licenses/mit-license.php 19 | * http://www.gnu.org/licenses/gpl.html 20 | * 21 | * USAGE: 22 | * 23 | * $("#myObject").smartupdater({ 24 | * url : "foo.php" 25 | * }, function (data) { 26 | * //process data here; 27 | * } 28 | * ); 29 | * 30 | * Public functions: 31 | * $("#myObject").smartupdater("stop") 32 | * $("#myObject").smartupdater("restart"); 33 | * $("#myObject").smartupdater("setTimeout",timeout); 34 | * $("#myObject").smartupdater("alterUrl"[,"foo.php"[,data]]); 35 | * $("#myObject").smartupdater("alterCallback"[, foo]); 36 | * 37 | * Public Attributes: 38 | * var status = $("#myObject").smartupdater("getState"); 39 | * var timeout = $("#myObject").smartupdater("getTimeout"); 40 | * 41 | **/ -------------------------------------------------------------------------------- /content/api.html: -------------------------------------------------------------------------------- 1 |
2 |

List of available functions

3 | 98 | 99 |

List of available attributes

100 | 123 | 124 |

List of available options

125 | 355 | 356 |

List of available features

357 | 396 | 397 | 398 | 399 | 400 | 401 |
-------------------------------------------------------------------------------- /content/automatic_control.html: -------------------------------------------------------------------------------- 1 | 2 |

Automatic Control

3 | 4 | 5 |
6 | 7 |
8 | 9 |
Time on server:

10 |
Timeout: msec
11 |
12 | 13 | 14 | sec.   15 | 16 | 17 |
18 | 19 |
20 | 21 |
[ view code ]
22 |
23 |
[ X ]
24 |
 25 | <span class="data" id='example1'></span>
 26 | <input id="newTimeout" size="2" type="text" /> sec.  
 27 | <input type="button" value="set timeout" onclick="suSetTimeout()" />
 28 | 
 29 | $("#example1").smartupdater({
 30 |     url : 'php/automatic_control.php',
 31 |     minTimeout: 5000 // 5 seconds
 32 |     }, function (data) {
 33 |         $("#example1").html(data);
 34 |      }
 35 | );
 36 | 
 37 | function suSetTimeout() 
 38 | {
 39 | 	var timeout = $("#newTimeout").val() * 1000;
 40 | 	if (timeout < 1000) timeout = 1000;
 41 | 	$("#example1").smartupdater("setTimeout",timeout);
 42 | }
 43 | 
44 | <?php 45 | /* get client's feedback */ 46 | $aSmartupdater = json_decode($_SERVER['HTTP_X_SMARTUPDATER'], true); 47 | 48 | $xheader = false; 49 | if ( (int)$aSmartupdater["timeout"] < 5000) { 50 | $xheader = '{"timeout":"5000"}'; 51 | } 52 | if ((int)$aSmartupdater["timeout"] > 15000 ) { 53 | $xheader = '{"timeout":"15000"}'; 54 | } 55 | 56 | if($xheader) { 57 | header("X-Smartupdater:$xheader"); 58 | } 59 | echo date('h:i:s'); 60 | ?> 61 |
62 |
63 |
64 |
65 |
66 | 67 | 68 | 69 |
70 | 71 | 72 | 73 |

OK. Now let's create something really cool. For example - automatic control system, similar to space missile control... well, Volvo cruise control, why not? Maybe a bit simpler, however :)
74 | Sometimes, we want to keep clients' polling rate within pre-defined range to prevent server overloading from one hand and loosing customers data because of too slow polling from the other. 75 |

76 |

77 | As we know, key point for every automatic control system is feedback. And Smartupdater has this feature. Every cycle Smartupdater sends current polling rate to server and (as you already know) server can re-program Smartupdater (see "Remote Timeout"). 78 | To organize feedback Smartupdater uses custom HTTP header X-Smartupdater and sends data with this header 79 | data: JSON 80 |

81 | In this example server keeps Smatrupdater timeout within range 5 - 15 sec. If you set it less then 5 sec, server re-set it to 5 sec in the next polling cycle. If you set timeout greater then 15 sec. server re-set it to 15 sec in the next cycle. No Smartupdater setting is needed. 82 |

83 | 84 | 85 |
86 | 87 | 110 | -------------------------------------------------------------------------------- /content/complex_alternation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Complex Alternation

4 | 5 | 6 | 7 |
8 | 9 |
10 | 11 |
Time on server:
12 |
13 | 14 |     15 | 16 | 17 | 18 | 19 |
20 | 21 |
22 | 23 |
[ view code ]
24 |
25 |
[ X ]
26 |
 27 | <span class="data" id='example1'></span>
 28 | <input type="button" value="default" onclick='configDefault()' />
 29 | <input type="button" value="getmin.php/foo( )" onclick='configAlter()'  />
 30 | 
 31 | $("#example1").smartupdater({
 32 | 	url : 'php/getsec.php',
 33 | 	minTimeout: 2000 // 2 seconds
 34 | 	}, function (data) {
 35 | 		$("#example1").html(data);
 36 | 	}
 37 | );
 38 | 
 39 | function configDefault()
 40 | {
 41 | 	$("#example1").smartupdater("alterCallback")
 42 | 			.smartupdater("alterUrl")
 43 | 			.smartupdater("restart");
 44 | }
 45 | 	
 46 | function configAlter()
 47 | {
 48 | 	$("#example1").smartupdater("alterCallback", foo)
 49 | 			.smartupdater("alterUrl","php/getmin.php",{"arg":"admin","value":0})
 50 | 			.smartupdater("restart");
 51 | }
 52 | 	
 53 | function foo(data) {
 54 | 	$("#example1").html("foo ( "+data.split(":").reverse().join(":")+ " )");
 55 | }
 56 | 
57 |
58 |
59 |
60 | 61 | 62 | 63 |
64 | 65 | 66 | 67 |

68 | Complex alternation let you to associate URL with dedicated callback function and dynamically apply this configuration. 69 | For example, if your module is opened, you poll url "getData.php" and process result with callback function "processData()". 70 | But if the module is minimized, you poll url "getAlert.php" and process result with callback function "processAlert()". 71 | Using this feature you easily can create event-driven polling engine. 72 |

73 |

In this example you can see how to switch between two Smartupdater configurations. 74 | It's not necessary to restart Smartupdater after it was 75 | altered, but if you want to update view immediately, do restart it. 76 | 77 |

78 | 79 | 80 | 81 |
82 | 83 | 114 | -------------------------------------------------------------------------------- /content/dynamic_callback.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Dynamic Callback

4 | 5 | 6 | 7 |
8 | 9 |
10 | 11 |
Time on server:
12 |
13 | 14 | 16 | 17 |     18 | 19 | 20 | 21 | 22 |
23 | 24 |
25 | 26 |
[ view code ]
27 |
28 |
[ X ]
29 |
30 | <span class="data" id='example1'></span><
31 | <input type="button" value="default" onclick='$("#example1")
32 | 				.smartupdater("alterCallback")
33 | 				.smartupdater("restart");' />
34 | 		
35 | <input type="button" value="foo()" onclick='$("#example1")
36 | 				.smartupdater("alterCallback", foo)
37 | 				.smartupdater("restart");' />
38 | 
39 | $("#example1").smartupdater({
40 |     url : 'php/getsec.php',
41 |     minTimeout: 5000 // 5 seconds
42 |     }, function (data) {
43 | 	$("#example1").html(data);
44 |     }
45 | );
46 | 
47 | function foo(data) 
48 | {
49 |     $("#example1").html(data.split("").reverse().join(""));
50 | }
51 | 
52 |
53 |
54 |
55 | 56 | 57 | 58 |
59 | 60 | 61 | 62 |

63 | If you develop complex application, very often you need to process the same data differently depend on 64 | current layout, state, user preferences or other conditions. With Smartupdater you can easily swithch among multiple 65 | callback function, which makes your code very modular, flexible and clean. 66 |

67 |

In this example you can see date in regular and reverse order. It's not necessary to restart smartupdater after it was 68 | altered, but if you want to update view immediately, do restart it. 69 | 70 |

71 | 72 | 73 | 74 |
75 | 76 | 93 | -------------------------------------------------------------------------------- /content/dynamic_timeout.html: -------------------------------------------------------------------------------- 1 | 2 |

Dynamic Timeout

3 | 4 | 5 |
6 | 7 |
8 | 9 |
Time on server:
10 |
11 | 12 | 13 | sec.   14 | 15 | 16 | 17 | 18 |
19 | 20 |
21 | 22 |
[ view code ]
23 |
24 |
[ X ]
25 |
26 | <span class="data" id='example1'></span>
27 | <input id="newTimeout" size="2" type="text" /> sec.  
28 | <input type="button" value="set timeout" onclick="suSetTimeout()" />
29 | 
30 | $("#example1").smartupdater({
31 |     url : 'php/getsec.php',
32 |     minTimeout: 5000 // 5 seconds
33 |     }, function (data) {
34 |         $("#example1").html(data);
35 |     }
36 | );
37 | 	
38 | function suSetTimeout() 
39 | {
40 |     var timeout = $("#newTimeout").val() * 1000;
41 |     $("#example1").smartupdater("setTimeout",timeout);
42 | }
43 | 
44 |
45 |
46 |
47 | 48 | 49 | 50 |
51 | 52 | 53 | 54 |

At any time you can set any timeout which is right for current task your application is executing. See how it works in this demo. (Set interval in seconds, not milliseconds)

55 | 56 | 57 | 58 |
59 | 60 | 81 | 82 | -------------------------------------------------------------------------------- /content/dynamic_url.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |

Dynamic URL

4 | 5 | 6 |
7 | 8 |
9 | 10 |
Time on server:
11 |
12 | 13 | 15 | 16 |     17 | 18 | 19 |
20 | 21 |
22 | 23 |
[ view code ]
24 |
25 |
[ X ]
26 |
27 | <input type="button" value="default" onclick='$("#example1")
28 |             .smartupdater("alterUrl")
29 |             .smartupdater("restart");' />
30 | 			
31 | <input type="button" value="getsecreverse.php" onclick='$("#example1")
32 |             .smartupdater(alterUrl","php/getsecreverse.php",{"arg":"admin","value":0})
33 |             .smartupdaterRestart();' />
34 | 
35 | $("#example1").smartupdater({
36 |     url : 'php/getsec.php',
37 |     minTimeout: 5000 // 2 seconds
38 |     }, function (data) {
39 |         $("#example1").html(data);
40 |     }
41 | );
42 | 
43 | 
44 |
45 |
46 |
47 | 48 | 49 | 50 |
51 | 52 |

53 | Another case: depend on current layout, state, user preferences or other conditions you want to request different data. 54 | For example, user iconized module: you don't need request regular data any more, but want to poll alerts or notification only. 55 | With Smartupdater you can easily switch among multiple URLs, which makes your code very modular, flexible and clean. 56 |

57 |

In this example you can poll either regular getsec.php or funny reverse date layout. It's not necessary to restart smartupdater after it was 58 | altered, but if you want to update view immediately, do restart it. 59 | 60 |

61 | 62 | 63 | 64 |
65 | 66 | 77 | -------------------------------------------------------------------------------- /content/failures_handling.html: -------------------------------------------------------------------------------- 1 | 2 |

Failures Handling

3 | 4 | 5 |
6 | 7 |
8 | 9 |
Time on server:
10 |
Smartpdater State:
11 |
12 | 13 | 14 |
15 | 16 |
17 | 18 |
[ view code ]
19 |
20 |
[ X ]
21 |
22 | <div id='example1'></div>
23 | <div id="statusSU"></div>
24 | 
25 | $("#example1").smartupdater({
26 | 	url : 'php/fake.php',
27 | 	maxFailedRequests : 3,
28 | 	maxFailedRequestsCb : function(xhr, textStatus, errorThrown){
29 | 				alert("callback function maxFailedRequestsCb() is called");
30 | 			},
31 | 	minTimeout: 5000 // 5 seconds
32 | 	}, function (data) {
33 | 		$("#example1").html(data);
34 | 	}
35 | );
36 | 	
37 | <input onclick='$("#example1").smartupdater("restart");' type="button" value="Restart" />
38 | 
39 | 
40 |
41 |
42 |
43 | 44 | 45 | 46 |
47 | 48 | 49 |

If for some reasons URL doesn't response, you don't want to continue to poll it, right? Smartupdater takes care of it. Use "maxFailedRequests" option to set max allowed number of consecutive ajax failures and Smartupdater stops polling after this number of failed requests

50 |

In this example maxFailedRequests is set to 3, Smartupdater polls url which doesn't exist and gets errors as return. It stops after 3 polling cycles (15 sec).

51 | 52 |
53 | 54 | 71 | -------------------------------------------------------------------------------- /content/http_cache.html: -------------------------------------------------------------------------------- 1 | 2 |

HTTP cache (304 Not Modified)

3 | 4 | 5 | 6 |
7 | 8 |
9 | 10 | 11 |

12 | 13 |
14 | 15 |
16 | 17 |
[ view code ]
18 |
19 |
[ X ]
20 |
 21 | <input id="example1" type="text" value="" />
 22 | 
 23 | $("#example1").smartupdater({
 24 | 	url : 'php/getmin_cache_etag.php',
 25 | 	minTimeout: 5000, // 5 seconds 
 26 | 	httpCache: true 
 27 | 	}, function (data) {
 28 | 		$("#example1").val(data);
 29 | 	}
 30 | );
 31 | 
 32 | 
33 | <?php 34 | $servertime = date('h:i'); 35 | $checksum = md5($servertime); 36 | header("ETag:$checksum"); 37 | if($checksum != $_SERVER['HTTP_IF_NONE_MATCH']) { 38 | echo $servertime; 39 | } 40 | ?> 41 |
42 |
43 |
44 |
45 |
46 | 47 | 48 | 49 |
50 |

51 | This feature let you to save traffic. It allows the request to be successful only if 52 | the response has changed since the last request. This is done by checking the Last-Modified header. 53 | This technique also checks the 'etag' specified by the server to catch unmodified data. 54 |

55 |

56 | Those who are familiar with HTTP caching and already looked into the smartupdater source probable would 57 | like to ask me a couple of questions: 58 |

59 |
60 |

61 | Q. jQuery AJAX already has "ifModified" option to activate http cache feature. 62 | So, why do you re-invent the wheel? 63 |

64 | A. There is a bug in jQuery AJAX engine ( http://bugs.jquery.com/ticket/8095 ) and Smartupdater simply can't use this option. 65 |

66 | Q. You are talking about "304 Not Modified" http header, right? But neither your code example, nor your live demo 67 | shows any "304 Not Modified" http headers. LOL :) 68 |

69 | A. Yes, it's funny :) But there is another jQuery AJAX bug (or maybe not bug, but problem which is known as "Opera issue"). 70 | Briefly, the problem is: Opera's xhr object returns "304 Not Modified" header in non-standard format, so that jQuery AJAX engine can't interpret it correctly. That's why to avoid using "304" header, I have to implement caching algorithm directly in Smartupdater. 71 |

72 |
73 |

Please pay attention to the PHP code: Server doesn't send "304 Not Modified" header, but includes ETag header 74 | in each reply. Smartupdater gets this ETag, compares with previous one and if they are equal, process response 75 | as if it gets "304 Not Modified" header. 76 |

77 |

78 | Two http headers are used by Smartupdater to implement this feature: 79 | ( ETag / If-None-Match) and ( Last-Modified / If-Modified-Since). They are processed identically, but ETag is more 80 | suitable for cache validation (check if content is the same), while Last-Modified more suitable for checking cache 81 | freshness ( check content time or revision number). 82 |

83 | Server sends headers ETag or Last-Modified and Smartupdater returns the data in If-None-Match or If-Modified-Since headers. 84 |

85 | Open debugger and check network activity. You see, that client sends requests every 5 seconds, but server responses with actual data only once in a minute. The rest server's responses have header and empty message body. 86 | 87 |
88 | 89 | 100 | -------------------------------------------------------------------------------- /content/overview.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |

Smartupdater plugin performs periodical updating functionality and can be used in all sorts of applications which need polling mechanisms.

4 |
5 | Smartupdater 4.0 has exactly the same functionality as version 3.2. The difference is API style. Because API has been changed, use this version only for new projects. Don't upgrade existing projects with version 4.0 as APIs 3.xx and 4.0 are incompatible. 6 |
7 |
8 | 9 | 10 | 11 | 12 |
13 | 59 |
60 | 61 |
62 | 98 |
99 | 100 | -------------------------------------------------------------------------------- /content/remote_callback.html: -------------------------------------------------------------------------------- 1 | 2 |

Remote Callback

3 | 4 | 5 |
6 | 7 |
8 | 9 |
Time on server:
10 |
11 | 12 |
13 | 14 |
15 | 16 |
[ view code ]
17 |
18 |
[ X ]
19 |
20 | <span class="data" id='example1'></span>
21 | 
22 | $("#example1").smartupdater({
23 | 	url : 'php/remote_callback.php',
24 | 	minTimeout: 5000, // 5 seconds
25 | 	rCallback: 'foo,bar'
26 | 	}, function (data) {
27 | 		$("#example1").html(data);
28 | 	}
29 | );
30 | 
31 | function foo(data) {
32 |     $("#example1").html("foo( "+data+ ")");
33 | }
34 | function bar(data) {	
35 |     var img = "";
36 |     $("#example1").html("bar( "+data.split("").reverse().join("")+")"+img);
37 | }
38 | 
39 | 
40 | <?php 41 | $callback = (date('s')<30) ? "foo" : "bar"; 42 | $xheader = '{"callback":"'.$callback.'"}'; 43 | header("X-Smartupdater:$xheader"); 44 | echo date('h:i:s'); 45 | ?> 46 |
47 |
48 |
49 |
50 |
51 | 52 | 53 | 54 |
55 | 56 | 57 | 58 |

Data structure and data format which server sends to client can vary. For example, server sends client only new data it gets since last response. But occasionally old data can be changed (something deleted or modified) and server need a way to instruct client to process this particular piece of data differently.

59 |

60 |

Smartupdater lets you to set callback function from a server.

61 | 62 |

Instead of adding extra field (command field) to the data frame, parse the field on client side, extract command and process data according this command, you can simply instruct Smartupdater which callback function should process this piece of data.

63 |

64 | In this example server checks current seconds and if it less then 40 sec. function foo() as a callback function, otherwise function bar() is set. 65 |

66 | To activate this feature set option rCallback with list of of function which server is allowed to set as callback. This list is a string with comma-separated function names. 67 |

68 |

69 | To implement this feature Smartupdater uses custom HTTP header "X-Smartupdater". Value for the header is built in JSON format 70 |

71 |
72 | 73 | 95 | -------------------------------------------------------------------------------- /content/remote_timeout.html: -------------------------------------------------------------------------------- 1 | 2 |

Remote Timeout

3 | 4 | 5 |
6 | 7 |
8 | 9 |
Time on server:
10 |
11 |
Timeout: msec
12 |
13 | 14 |
15 | 16 |
17 | 18 |
[ view code ]
19 |
20 |
[ X ]
21 |
22 | <span class="data" id='example1'></span>
23 | 
24 | $("#example1").smartupdater({
25 | 	url : 'php/remote_timeout.php',
26 | 	minTimeout: 5000 // 5 seconds
27 | 	}, function (data) {
28 | 		$("#example1").html(data);
29 | 	}
30 | );
31 | 
32 | <?php 33 | $timeout = (date('i')%2) ? 5000 : 20000; 34 | $xheader = '{"timeout":"'.$timeout.'"}'; 35 | header("X-Smartupdater:$xheader"); 36 | echo date('h:i'); 37 | ?> 38 |
39 |
40 |
41 |
42 |
43 | 44 | 45 | 46 |
47 | 48 | 49 | 50 |

Everybody who has deal with polling systems knows, that server can be easily overloaded with client-side requests, so we try to set polling period as low as possible. But if number users grows, we have to either increase polling period and make our application less dynamic or spend money on either upgrading hardware or buying additional resources from service provider.

51 |

52 | Smartupdater lets you to re-program timeout from a server. 53 |

58 |

59 | In this example server checks current minute and if it even sets timeout to 20 sec., 60 | and if it odd sets it to 5 sec (shown in milliseconds). 61 |

62 | To implement this feature Smartupdater uses custom HTTP header "X-Smartupdater". 63 | Value for the header is built in JSON format 64 |

65 | 66 |
67 | 68 | 83 | -------------------------------------------------------------------------------- /content/smart_stop.html: -------------------------------------------------------------------------------- 1 |

Smart Stop

2 |

3 | This feature can significantly improve application performance on both server and client and reduce network traffic. 4 |

5 |
6 | 7 |
8 | 9 |
10 |
11 | | 12 | | 13 | 14 | | 15 | 16 |
17 |
18 | 19 |
20 |
21 | ×   22 |
23 | 24 |

Foo

25 |
26 |
27 | 28 |
29 |
×  
30 | 31 | 32 |

Bar

33 |
34 |
35 | 36 |
37 | 38 |
39 |
40 |
41 | 42 |
[ view code ]
43 |
44 |
[ X ]
45 | 46 |
 47 | 
 48 | <div id="foo" class="ui-widget-content smartStop">
 49 | 	<div class="closeButton" style="inline-block" onclick="$(this).parent().remove();"> × </div>
 50 | 	<img class="resizeButton"  src="img/collapse-expand2.jpg"/>
 51 | 	<h3 class="ui-widget-header">Foo</h3>
 52 | 	<div class="content"></div>
 53 | </div>		
 54 | 
 55 | <div id="bar" class="ui-widget-content smartStop">
 56 | 	<div class="closeButton" style="inline-block" onclick="$(this).parent().remove();"> × </div>
 57 | 	<img class="resizeButton"  src="img/collapse-expand2.jpg"/>
 58 | 	<h3 class="ui-widget-header">Bar</h3>
 59 | 	<div class="content"></div>
 60 | </div>	
 61 | 
 62 | 
 63 | $("#foo").smartupdater({
 64 | 		url : 'php/getsec_foo.php',
 65 | 		minTimeout: 4000, 
 66 | 		smartStop: {active:true, monitorTimeout:1500,minHeight:100,minWidth:100}
 67 | 	}, function (data) {
 68 | 			$("#foo > .content").html(data);
 69 | 		}
 70 | );
 71 | 		
 72 | $("#bar").smartupdater({
 73 | 		url : 'php/getsec_bar.php',
 74 | 		minTimeout: 4000, 
 75 | 		smartStop: {active:true, monitorTimeout:1500,minHeight:100,minWidth:100}
 76 | 	}, function (data) {
 77 | 			$("#bar > .content").html(data);
 78 | 		}
 79 | );
 80 | 
81 |
82 |
83 | 84 |
85 | 86 |
87 |
88 |

89 | It's simple: automatically stop polling if the result can not be visible and restart it as soon as it can be visible again. 90 | But when result can not be visible? 91 |

92 |

93 | - module is minimized or set too small to display result.
94 | - module is invisible ( set display:none) 95 | 96 |

97 | Smartupdater automatically checks element's size and visibility and stops/restarts itself based on the element's state. 98 |
99 | If you use "Accordion" technique or multi-table view or let users to minimize modules to get more space - consider to activate "smartStop" feature. 100 |

101 | 102 |

103 | In this example minHeight=100px and minWidth=100px.
104 | Resize these modules manually, minimize/maximize them with button, hide/show one or both of them and check network activity. 105 |

106 |
107 |
108 | 109 | 127 | 128 | -------------------------------------------------------------------------------- /content/smart_updating.html: -------------------------------------------------------------------------------- 1 | 2 |

Smart Updating

3 | 4 | 5 | 6 |
7 | 8 |
9 | 10 | 11 |

12 | 13 |
14 | 15 |
16 | 17 |
[ view code ]
18 |
19 |
[ X ]
20 |
21 | <input id="example1" type="text" value="" />
22 | 
23 | $("#example1").smartupdater({
24 | 	url : 'php/getmin.php',
25 | 	minTimeout: 5000 // 5 seconds
26 | 	}, function (data) {
27 | 		$("#example1").val(data);
28 | 	}
29 | );
30 | 	
31 | 
32 |
33 |
34 |
35 | 36 | 37 | 38 |
39 | 40 | 41 | It is a very basic feature. If data isn't changed, Smartupdater doesn't update client side GUI. 42 | It simply doesn't call callback function. 43 | In this example server returns hours and minutes, so data from server is changed every minute. Because I set poll 44 | interval 5 sec. server returns the same data 11 times. But Smartupdater ignors the data and doesn't update view. 45 | You can clear input field or type something in it to see that date is refreshed 1 time in a minute 46 | 47 | 48 |
49 | 50 | 62 | -------------------------------------------------------------------------------- /content/stop_restart.html: -------------------------------------------------------------------------------- 1 | 2 |

Stop and Continue

3 | 4 | 5 |
6 | 7 |
8 | 9 |
Time on server:
10 |
Smartpdater State:
11 |
12 | 13 | 14 | 15 |
16 | 17 |
18 | 19 |
[ view code ]
20 |
21 |
[ X ]
22 |
23 | <div id='example1'></div>
24 | <div id="statusSU"></div>
25 | 
26 | $("#example1").smartupdater({
27 | 	url : 'php/getsec.php',
28 | 	minTimeout: 2000 // 2 seconds
29 | 	}, function (data) {
30 | 		$("#example1").html(data);
31 | 	}
32 | );
33 | 	
34 | <input onclick='$("#example1").smartupdater("stop")'    type="button" value="Stop"    />
35 | <input onclick='$("#example1").smartupdater("restart")' type="button" value="Restart" />
36 | 
37 | 
38 |
39 |
40 |
41 | 42 | 43 | 44 |
45 | 46 | 47 | Sometimes you want to stop polling and continue it later. For example if user minimizes an active object or enlarges another object which covers the active one you don't want to to keep polling as it simply wasting both server and client resources. Smartupdater lets you to stop polling and continue it as needed. 48 | 49 | 50 |
51 | 52 | 65 | -------------------------------------------------------------------------------- /img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/close.png -------------------------------------------------------------------------------- /img/close_hover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/close_hover.png -------------------------------------------------------------------------------- /img/close_pushed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/close_pushed.png -------------------------------------------------------------------------------- /img/clown.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/clown.gif -------------------------------------------------------------------------------- /img/collapse-expand.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/collapse-expand.jpg -------------------------------------------------------------------------------- /img/collapse-expand2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/collapse-expand2.jpg -------------------------------------------------------------------------------- /img/collapse-expand3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/collapse-expand3.gif -------------------------------------------------------------------------------- /img/collapse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/collapse.png -------------------------------------------------------------------------------- /img/demo-spindown-closed.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/demo-spindown-closed.gif -------------------------------------------------------------------------------- /img/demo-spindown-open.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/demo-spindown-open.gif -------------------------------------------------------------------------------- /img/expand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/expand.png -------------------------------------------------------------------------------- /img/expand2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vkiryukhin/Smartupdater/660cbb3ac780812d64a26d43068115d0f0ee6cc6/img/expand2.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Smartupdater - jQuery periodical updater 24 | 25 | 26 | 27 | 28 | 29 | 42 | 43 | 44 |
45 | 46 | 47 | 72 | 73 | 74 | 75 |
content here
76 | 77 |
78 | 79 |
80 | 81 | 82 |
83 | 84 |

85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /main.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | padding:10px; 4 | font: .875em/1.286 "Lucida Grande", "Lucida Sans Unicode", Lucida, Arial, Helvetica, sans-serif; 5 | color: #333; 6 | background:#FFFFF0;} 7 | 8 | h1, h2, h3 {text-align:center; color:#000080;} 9 | p {margin:10px; padding:5px;} 10 | code {color:#000080; /*font-weight:bold;*/font-size:110%;fint-style:italic;} 11 | pre {font-size:120%;/*font-family: monospace;color:#000033; font-weight:bold;*/} 12 | a:link {color:black;} 13 | a:visited {color:black;} 14 | 15 | #header { min-height:50px; position:relative; border:0px solid red; } 16 | #header ul { text-align:center; margin-top:15px; margin-bottom:5px; background:#E8E8FF;} 17 | #header ul li { display:inline; margin-left:10px; position:relative;} 18 | #header ul li { cursor:pointer; } 19 | #header ul li:hover { color:#ff0000;} 20 | #header ul li a:hover {color:red;} 21 | 22 | #container { min-width:800px; border:0px solid green;} 23 | 24 | #menu { width:20%; float:left; margin:5px; border:0px solid blue; background:#E8E8FF; padding:1%} 25 | #menu ul li ul li { cursor:pointer;} 26 | #menu ul li ul li:hover {color:#ff0000;} 27 | 28 | #content { width:77%; float:left; min-height:20px; border:0px solid black; } 29 | 30 | #footer { height:50px; text-align:center;color:#999999;font-size:70%;} 31 | 32 | #leftpanel { float:left;} 33 | 34 | #demopanel {background:#f0fff0; margin:10px;padding:10px;} 35 | #codepanel { 36 | background-color:#ffffe0; 37 | margin-left:10px; 38 | margin-right:15px; 39 | padding-left:10px; 40 | } 41 | .codecontrol { cursor:pointer; margin-bottom:10px; color:#808080; font-size:85%;} 42 | .codesource { 43 | display:none; background:#ffffe0; position:absolute; z-index:100; padding:15px; 44 | border-top:5px solid #cccccc; border-left:5px solid #cccccc; 45 | border-bottom:4px solid #333333;border-right:4px solid #333333; 46 | padding:10px; 47 | } 48 | .close_button { 49 | color:#cc0000; 50 | cursor:pointer; 51 | font-weight:bold; 52 | position:relative; 53 | left:90%; 54 | } 55 | .data {font-weight:bold;color:#0000CC;} 56 | 57 | .leftcolumn { float:left; width:49%; } 58 | .rightcolumn {float:left; width:49%;} 59 | 60 | 61 | .leftcolumn ul li {color:#000080; margin:15px;font-weight:bold;} 62 | .leftcolumn ul li ul li {color:#333333; margin:5px;font-weight:normal;} 63 | 64 | .rightcolumn ul li {color:#800000; margin:15px;font-weight:bold;} 65 | .rightcolumn ul li ul li {color:#333333; margin:5px;font-weight:normal;} 66 | 67 | a:hover {color:#ff0000;} 68 | a:link {color:black;} 69 | a:visited {color:black;} 70 | 71 | .menu_selected { 72 | background:#FFFFf0; 73 | } 74 | 75 | .php_code { 76 | background-color:#F0F0ff; 77 | margin:5px; 78 | } 79 | .option { 80 | color:#0000ff; 81 | /*font-weight:bold;*/ 82 | text-size:80%; 83 | } 84 | 85 | #apiDoc { 86 | 87 | } 88 | #apiDoc ul { 89 | list-style-type:none; 90 | } 91 | .apiDocToggleBtn { 92 | margin-right:10px; 93 | } 94 | .apiDetails { 95 | display:none; 96 | background:#ffffd8; 97 | margin:10px; 98 | padding: 10px; 99 | border:1px solid black; 100 | } 101 | .toggleApiDetails { 102 | background-image: url("img/demo-spindown-closed.gif"); 103 | background-repeat:no-repeat; 104 | padding-left: 15px; 105 | cursor:pointer; 106 | } -------------------------------------------------------------------------------- /main.js: -------------------------------------------------------------------------------- 1 | 2 | var hInterval = 0; 3 | 4 | $(document).ready(function() 5 | { 6 | $('li[data-content]').bind('click', function(event) { 7 | var url = $(this).attr('data-content'); 8 | clearInterval(hInterval); 9 | $('#content').empty(); 10 | 11 | $.ajax( { 12 | url: url, 13 | dataType: "html", 14 | cache : false, 15 | success: function(data) { 16 | $('#content').html(data); 17 | } 18 | }); 19 | 20 | //$('li[data-content]').removeClass("menu_selected"); 21 | //$(this).addClass("menu_selected"); 22 | }); 23 | 24 | $('#content').empty().load("content/overview.html"); 25 | 26 | 27 | }); 28 | 29 | function updateStatus(mode) 30 | { 31 | var statusSU = document.getElementById("statusSU"); 32 | if(statusSU) { 33 | //$("#statusSU").html($("#example1")[0].smartupdaterStatus.state); 34 | $("#statusSU").html($("#example1").smartupdater("getState")); 35 | } else { 36 | clearInterval(hInterval); 37 | } 38 | } 39 | 40 | function updateTimeoutStatus(mode) 41 | { 42 | var statusSU = document.getElementById("statusSU"); 43 | if(statusSU) { 44 | //$("#statusSU").html($("#example1")[0].smartupdaterStatus.timeout); 45 | $("#statusSU").html($("#example1").smartupdater("getTimeout")); 46 | } else { 47 | clearInterval(hInterval); 48 | } 49 | } 50 | 51 | function toggleApiDetails(obj) { 52 | var re = /closed/; 53 | var state = $(obj).css("background-image"); 54 | if (state.search(re) != -1) { 55 | $(obj).css("background-image",'url("img/demo-spindown-open.gif")'); 56 | $(obj).children(".apiDetails").css("display","block"); 57 | } else { 58 | $(obj).css("background-image",'url("img/demo-spindown-closed.gif")'); 59 | $(obj).children(".apiDetails").css("display","none"); 60 | } 61 | } -------------------------------------------------------------------------------- /php/automatic_control.php: -------------------------------------------------------------------------------- 1 | 15000 ) { 10 | $xheader = '{"timeout":"15000"}'; 11 | } 12 | 13 | if($xheader) { 14 | header("X-Smartupdater:$xheader"); 15 | } 16 | echo date('h:i:s'); 17 | ?> 18 | -------------------------------------------------------------------------------- /php/getmin.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /php/getmin_cache_control.php: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /php/getmin_cache_etag.php: -------------------------------------------------------------------------------- 1 | 9 | -------------------------------------------------------------------------------- /php/getsec.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /php/getsec_bar.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /php/getsec_foo.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /php/getsecreverse.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /php/gettimestamp.php: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /php/remote_callback.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /php/remote_timeout.php: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /smartupdater.js: -------------------------------------------------------------------------------- 1 | /** 2 | * smartupdater - jQuery Plugin 3 | * 4 | * Version - 4.0 5 | * Copyright (c) 2010 - 2012 Vadim Kiryukhin 6 | * vkiryukhin @ gmail.com 7 | * 8 | * http://www.eslinstructor.net/smartupdater/ 9 | * 10 | * Dual licensed under the MIT and GPL licenses: 11 | * http://www.opensource.org/licenses/mit-license.php 12 | * http://www.gnu.org/licenses/gpl.html 13 | * 14 | * USAGE: 15 | * 16 | * $("#myObject").smartupdater({ 17 | * url : "foo.php" 18 | * }, function (data) { 19 | * //process data here; 20 | * } 21 | * ); 22 | * 23 | * Public functions: 24 | * $("#myObject").smartupdater("stop") 25 | * $("#myObject").smartupdater("restart"); 26 | * $("#myObject").smartupdater("setTimeout",timeout); 27 | * $("#myObject").smartupdater("alterUrl"[,"foo.php"[,data]]); 28 | * $("#myObject").smartupdater("alterCallback"[, foo]); 29 | * 30 | * Public Attributes: 31 | * var status = $("#myObject").smartupdater("getState"); 32 | * var timeout = $("#myObject").smartupdater("getTimeout"); 33 | * 34 | **/ 35 | 36 | (function($) { 37 | 38 | 39 | var methods = { 40 | 41 | init : function( options, callback) { 42 | return this.each(function () { 43 | var elem = this, 44 | es = {}; 45 | 46 | elem.settings = jQuery.extend(true,{ 47 | url : '', // see jQuery.ajax for details 48 | type : 'get', // see jQuery.ajax for details 49 | data : '', // see jQuery.ajax for details 50 | dataType : 'text', // see jQuery.ajax for details 51 | 52 | minTimeout : 60000, // 1 minute 53 | maxFailedRequests : 10, // max. number of consecutive ajax failures 54 | maxFailedRequestsCb : false, // falure callback function 55 | httpCache : false, // http cache 56 | rCallback : false, // remote callback functions 57 | selfStart : true, // start automatically after initializing 58 | smartStop : { active: false, //disabled by default 59 | monitorTimeout: 2500, // 2.5 seconds 60 | minHeight: 1, // 1px 61 | minWidth: 1 // 1px 62 | } 63 | 64 | }, options); 65 | 66 | elem.smartupdaterStatus = {state:'',timeout:0}; 67 | 68 | es = elem.settings; 69 | 70 | es.prevContent = ''; 71 | es.failedRequests = 0; 72 | es.etag = '0'; 73 | es.lastModified = '0'; 74 | es.callback = callback; 75 | es.origReq = {url:es.url,data:es.data,callback:callback}; 76 | es.stopFlag = false; 77 | 78 | 79 | function start() { 80 | 81 | /* check if element has been deleted and clean it up */ 82 | if(!$(elem).parents('body').length) { 83 | clearInterval(elem.smartupdaterStatus.smartStop); 84 | clearTimeout(elem.settings.h); 85 | elem = {}; 86 | return; 87 | } 88 | 89 | $.ajax({ 90 | url : es.url, 91 | type : es.type, 92 | data : es.data, 93 | dataType: es.dataType, 94 | cache : false, // MUST be set to false to prevent IE caching issue. 95 | 96 | success: function (data, statusText, xhr) { 97 | 98 | var dataNotModified = false, 99 | rCallback = false, 100 | xSmart = jQuery.parseJSON(xhr.getResponseHeader("X-Smartupdater")), 101 | xhrEtag, xhrLM; 102 | 103 | if(xSmart) { // remote control 104 | 105 | /* remote timeout */ 106 | es.minTimeout = xSmart.timeout ? xSmart.timeout : es.minTimeout; 107 | 108 | /* remote callback */ 109 | rCallback = xSmart.callback ? xSmart.callback : false; 110 | } 111 | 112 | if(es.httpCache) { // http cache process here 113 | 114 | xhrEtag = xhr.getResponseHeader("ETag"); 115 | xhrLM = xhr.getResponseHeader("Last-Modified"); 116 | 117 | dataNotModified = (es.etag == xhrEtag || es.lastModified == xhrLM) ? true : false; 118 | es.etag = xhrEtag ? xhrEtag : es.etag; 119 | es.lastModified = xhrLM ? xhrLM : es.lastModified; 120 | } 121 | 122 | if ( dataNotModified || 123 | es.prevContent == xhr.responseText || 124 | xhr.status == 304 ) { // data is not changed 125 | 126 | if(!es.stopFlag) { 127 | clearTimeout(es.h); 128 | es.h = setTimeout(start, es.minTimeout); 129 | } 130 | 131 | } else { // data is changed 132 | 133 | /* cache response data */ 134 | es.prevContent = xhr.responseText; 135 | 136 | /* reset timeout */ 137 | if(!es.stopFlag) { 138 | clearTimeout(es.h); 139 | es.h = setTimeout(start, es.minTimeout); 140 | } 141 | 142 | /* run callback function */ 143 | if(es.rCallback && rCallback && es.rCallback.search(rCallback) != -1) { 144 | window[rCallback](data); 145 | } else { 146 | es.callback(data); 147 | } 148 | } 149 | 150 | elem.smartupdaterStatus.timeout = es.minTimeout; 151 | es.failedRequests = 0; 152 | }, 153 | 154 | error: function(xhr, textStatus, errorThrown) { 155 | if ( ++es.failedRequests < es.maxFailedRequests ) { 156 | 157 | /* increment falure counter and reset timeout */ 158 | if(!es.stopFlag) { 159 | clearTimeout(es.h); 160 | es.h = setTimeout(start, es.minTimeout); 161 | elem.smartupdaterStatus.timeout = es.minTimeout; 162 | } 163 | 164 | } else { 165 | 166 | /* stop smartupdater */ 167 | clearTimeout(es.h); 168 | elem.smartupdaterStatus.state = 'OFF'; 169 | if( typeof(es.maxFailedRequestsCb)==='function') { 170 | es.maxFailedRequestsCb(xhr, textStatus, errorThrown); 171 | } 172 | } 173 | }, 174 | 175 | beforeSend: function(xhr, settings) { 176 | 177 | if(es.httpCache) { 178 | 179 | /* set http cache-related headers */ 180 | xhr.setRequestHeader("If-None-Match", es.etag ); 181 | xhr.setRequestHeader("If-Modified-Since", es.lastModified ); 182 | } 183 | 184 | /* Feedback: Smartupdater sends it's current timeout to server */ 185 | xhr.setRequestHeader("X-Smartupdater", '{"timeout":"'+elem.smartupdaterStatus.timeout+'"}'); 186 | } 187 | }); 188 | 189 | elem.smartupdaterStatus.state = 'ON'; 190 | } 191 | 192 | es.fnStart = start; 193 | 194 | if(es.selfStart) { 195 | start(); 196 | } 197 | 198 | if(es.smartStop.active) { 199 | 200 | elem.smartupdaterStatus.smartStop = setInterval(function(){ 201 | 202 | // check if object has been deleted 203 | if(!$(elem).parents('body').length) { 204 | clearInterval(elem.smartupdaterStatus.smartStop); 205 | clearTimeout(elem.settings.h); 206 | elem = {}; 207 | return; 208 | } 209 | 210 | var $elem = $(elem); 211 | var width = $elem.width(), 212 | height = $elem.height(), 213 | hidden = $elem.is(":hidden"); 214 | 215 | //element has been expanded, so smartupdater should be re-started. 216 | if(!hidden && height > es.smartStop.minHeight && width > es.smartStop.minWidth 217 | && elem.smartupdaterStatus.state=="OFF") { 218 | $elem.smartupdater("restart"); 219 | } else 220 | //element has been minimized, so smartupdater should be stopped. 221 | if( (hidden || height <= es.smartStop.minHeight || width <= es.smartStop.minWidth) 222 | && elem.smartupdaterStatus.state=="ON") { 223 | $elem.smartupdater("stop"); 224 | 225 | } 226 | 227 | },es.smartStop.monitorTimeout); 228 | } 229 | 230 | }); 231 | 232 | },// init() 233 | 234 | stop : function () { 235 | return this.each(function () { 236 | this.settings.stopFlag = true; 237 | clearTimeout(this.settings.h); 238 | this.smartupdaterStatus.state = 'OFF'; 239 | }); 240 | }, 241 | 242 | restart : function () { 243 | return this.each(function () { 244 | this.settings.stopFlag = false; 245 | clearTimeout(this.settings.h); 246 | this.settings.failedRequests = 0; 247 | this.settings.etag = "0"; 248 | this.settings.lastModified = "0"; 249 | this.settings.fnStart(); 250 | }) 251 | }, 252 | 253 | setTimeout : function (period) { 254 | return this.each(function () { 255 | clearTimeout(this.settings.h); 256 | this.settings.minTimeout = period; 257 | this.settings.fnStart(); 258 | }); 259 | }, 260 | 261 | alterCallback : function (callback) { 262 | return this.each(function () { 263 | this.settings.callback = callback ? callback : this.settings.origReq.callback; 264 | }); 265 | }, 266 | 267 | alterUrl : function (url,data) { 268 | return this.each(function () { 269 | this.settings.url = url ? url : this.settings.origReq.url; 270 | this.settings.data = data ? data : this.settings.origReq.data; 271 | }); 272 | }, 273 | 274 | getTimeout : function () { 275 | return this[0].smartupdaterStatus.timeout; 276 | }, 277 | 278 | getState : function () { 279 | return this[0].smartupdaterStatus.state; 280 | } 281 | 282 | }; //methods 283 | 284 | jQuery.fn.smartupdater = function (options, callback) { 285 | 286 | if ( methods[options] ) { 287 | return methods[ options ].apply( this, Array.prototype.slice.call( arguments, 1 )); 288 | } else if ( typeof options === 'object' || ! method ) { 289 | return methods.init.apply( this, arguments ); 290 | } else { 291 | $.error( 'Method ' + options + ' does not exist on jQuery.smartupdater' ); 292 | } 293 | }; 294 | 295 | 296 | })(jQuery); 297 | --------------------------------------------------------------------------------