/** * smartupdater - jQuery Plugin * * Version - 4.0.beta * Copyright (c) 2010 - 2011 Vadim Kiryukhin * vkiryukhin @ gmail.com * * http://www.eslinstructor.net/smartupdater/ * * Dual licensed under the MIT and GPL licenses: * http://www.opensource.org/licenses/mit-license.php * http://www.gnu.org/licenses/gpl.html * * USAGE: * * $("#myObject").smartupdater({ * url : "foo.php" * }, function (data) { * //process data here; * } * ); * * Public functions: * $("#myObject").smartupdater("stop") * $("#myObject").smartupdater("restart"); * $("#myObject").smartupdater("setTimeout",timeout); * $("#myObject").smartupdater("alterUrl"[,"foo.php"[,data]]); * $("#myObject").smartupdater("alterCallback"[, foo]); * * Public Attributes: * var status = $("#myObject").smartupdater("getState"); * var timeout = $("#myObject").smartupdater("getTimeout"); * **/ (function($) { var methods = { init : function( options, callback) { return this.each(function () { var elem = this, es = {}; elem.settings = jQuery.extend(true,{ url : '', // see jQuery.ajax for details type : 'get', // see jQuery.ajax for details data : '', // see jQuery.ajax for details dataType : 'text', // see jQuery.ajax for details minTimeout : 60000, // 1 minute maxFailedRequests : 10, // max. number of consecutive ajax failures maxFailedRequestsCb : false, // falure callback function httpCache : false, // http cache rCallback : false, // remote callback functions selfStart : true, // start automatically after initializing smartStop : { active: false, //disabled by default monitorTimeout: 2500, // 2.5 seconds minHeight: 1, // 1px minWidth: 1 // 1px } }, options); elem.smartupdaterStatus = {state:'',timeout:0}; es = elem.settings; es.prevContent = ''; es.failedRequests = 0; es.etag = '0'; es.lastModified = '0'; es.callback = callback; es.origReq = {url:es.url,data:es.data,callback:callback}; es.stopFlag = false; function start() { /* check if element has been deleted and clean it up */ if(!$(elem).parents('body').length) { clearInterval(elem.smartupdaterStatus.smartStop); clearTimeout(elem.settings.h); elem = {}; return; } $.ajax({ url : es.url, type : es.type, data : es.data, dataType: es.dataType, cache : false, // MUST be set to false to prevent IE caching issue. success: function (data, statusText, xhr) { var dataNotModified = false, rCallback = false, xSmart = jQuery.parseJSON(xhr.getResponseHeader("X-Smartupdater")), xhrEtag, xhrLM; if(xSmart) { // remote control /* remote timeout */ es.minTimeout = xSmart.timeout ? xSmart.timeout : es.minTimeout; /* remote callback */ rCallback = xSmart.callback ? xSmart.callback : false; } if(es.httpCache) { // http cache process here xhrEtag = xhr.getResponseHeader("ETag"); xhrLM = xhr.getResponseHeader("Last-Modified"); dataNotModified = (es.etag == xhrEtag || es.lastModified == xhrLM) ? true : false; es.etag = xhrEtag ? xhrEtag : es.etag; es.lastModified = xhrLM ? xhrLM : es.lastModified; } if ( dataNotModified || es.prevContent == xhr.responseText || xhr.status == 304 ) { // data is not changed if(!es.stopFlag) { clearTimeout(es.h); es.h = setTimeout(start, es.minTimeout); } } else { // data is changed /* cache response data */ es.prevContent = xhr.responseText; /* reset timeout */ if(!es.stopFlag) { clearTimeout(es.h); es.h = setTimeout(start, es.minTimeout); } /* run callback function */ if(es.rCallback && rCallback && es.rCallback.search(rCallback) != -1) { window[rCallback](data); } else { es.callback(data); } } elem.smartupdaterStatus.timeout = es.minTimeout; es.failedRequests = 0; }, error: function(xhr, textStatus, errorThrown) { if ( ++es.failedRequests < es.maxFailedRequests ) { /* increment falure counter and reset timeout */ if(!es.stopFlag) { clearTimeout(es.h); es.h = setTimeout(start, es.minTimeout); elem.smartupdaterStatus.timeout = es.minTimeout; } } else { /* stop smartupdater */ clearTimeout(es.h); elem.smartupdaterStatus.state = 'OFF'; if( typeof(es.maxFailedRequestsCb)==='function') { es.maxFailedRequestsCb(xhr, textStatus, errorThrown); } } }, beforeSend: function(xhr, settings) { if(es.httpCache) { /* set http cache-related headers */ xhr.setRequestHeader("If-None-Match", es.etag ); xhr.setRequestHeader("If-Modified-Since", es.lastModified ); } /* Feedback: Smartupdater sends it's current timeout to server */ xhr.setRequestHeader("X-Smartupdater", '{"timeout":"'+elem.smartupdaterStatus.timeout+'"}'); } }); elem.smartupdaterStatus.state = 'ON'; } es.fnStart = start; if(es.selfStart) { start(); } if(es.smartStop.active) { elem.smartupdaterStatus.smartStop = setInterval(function(){ // check if object has been deleted if(!$(elem).parents('body').length) { clearInterval(elem.smartupdaterStatus.smartStop); clearTimeout(elem.settings.h); elem = {}; return; } var $elem = $(elem); var width = $elem.width(), height = $elem.height(), hidden = $elem.is(":hidden"); //element has been expanded, so smartupdater should be re-started. if(!hidden && height > es.smartStop.minHeight && width > es.smartStop.minWidth && elem.smartupdaterStatus.state=="OFF") { $elem.smartupdater("restart"); } else //element has been minimized, so smartupdater should be stopped. if( (hidden || height <= es.smartStop.minHeight || width <= es.smartStop.minWidth) && elem.smartupdaterStatus.state=="ON") { $elem.smartupdater("stop"); } },es.smartStop.monitorTimeout); } }); },// init() stop : function () { return this.each(function () { this.settings.stopFlag = true; clearTimeout(this.settings.h); this.smartupdaterStatus.state = 'OFF'; }); }, restart : function () { return this.each(function () { this.settings.stopFlag = false; clearTimeout(this.settings.h); this.settings.failedRequests = 0; this.settings.etag = "0"; this.settings.lastModified = "0"; this.settings.fnStart(); }) }, setTimeout : function (period) { return this.each(function () { clearTimeout(this.settings.h); this.settings.minTimeout = period; this.settings.fnStart(); }); }, alterCallback : function (callback) { return this.each(function () { this.settings.callback = callback ? callback : this.settings.origReq.callback; }); }, alterUrl : function (url,data) { return this.each(function () { this.settings.url = url ? url : this.settings.origReq.url; this.settings.data = data ? data : this.settings.origReq.data; }); }, getTimeout : function () { return this[0].smartupdaterStatus.timeout; }, getState : function () { return this[0].smartupdaterStatus.state; } }; //methods jQuery.fn.smartupdater = function (options, callback) { if ( methods[options] ) { return methods[ options ].apply( this, Array.prototype.slice.call( arguments, 1 )); } else if ( typeof options === 'object' || ! method ) { return methods.init.apply( this, arguments ); } else { $.error( 'Method ' + options + ' does not exist on jQuery.tooltip' ); } }; })(jQuery);