/** * smartupdater - jQuery Plugin * * Version - 3.1.00.beta * Copyright (c) 2011 Vadim Kiryukhin * vkiryukhin @ gmail.com * * http://www.eslinstructor.net/smartupdater3/ * * 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").smartupdaterStop(); * $("#myObject").smartupdaterRestart(); * $("#myObject").smartupdaterSetTimeout(); * $("#myObject").smartupdaterAlterUrl(); * $("#myObject").smartupdaterAlterCallback(); * * Public Attributes: * var smStatus = $("#myObject")[0].smartupdaterStatus.state; * var smTimeout = $("#myObject")[0].smartupdaterStatus.timeout; * **/ (function(jQuery) { jQuery.fn.smartupdater = 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 by default maxFailedRequests : 10, // max. number of consecutive ajax failures by default httpCache : false, // no http cache by default rCallback : false, // no remote callback functions by default 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(!jQuery(elem).parents('body').length) { clearInterval(elem.smartupdaterStatus.smartStop); clearTimeout(elem.settings.h); elem = {}; return; } jQuery.ajax({ url : es.url, type : es.type, data : es.data, dataType: es.dataType, cache : false, // MUST be set to false to prevent IE caching bug. 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'; } }, 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; start(); if(es.smartStop.active) { elem.smartupdaterStatus.smartStop = setInterval(function(){ // check if object has been deleted if(!jQuery(elem).parents('body').length) { clearInterval(elem.smartupdaterStatus.smartStop); clearTimeout(elem.settings.h); elem = {}; return; } var $elem = jQuery(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.smartupdaterRestart(); } 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.smartupdaterStop(); } },es.smartStop.monitorTimeout); } }); }; jQuery.fn.smartupdaterStop = function () { return this.each(function () { this.settings.stopFlag = true; clearTimeout(this.settings.h); this.smartupdaterStatus.state = 'OFF'; }); }; jQuery.fn.smartupdaterRestart = 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(); }); }; jQuery.fn.smartupdaterSetTimeout = function (period) { return this.each(function () { clearTimeout(this.settings.h); this.settings.minTimeout = period; this.settings.fnStart(); }); }; jQuery.fn.smartupdaterAlterCallback = function (callback) { return this.each(function () { this.settings.callback = callback ? callback : this.settings.origReq.callback; }); }; jQuery.fn.smartupdaterAlterUrl = 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; }); }; })(jQuery);