intercooler
Version:
Making AJAX as easy as anchor tags
2 lines • 14.7 kB
JavaScript
/*! intercooler 0.3.2 2014-05-01 */
;var Intercooler=Intercooler||function(){function _defineTransition(a,b){null==b.newContent&&(b.newContent=function(a,b,c,d){a.html(b),d()}),null==b.remove&&(b.remove=function(a){a.remove()}),null==b.show&&(b.show=function(a){a.show()}),null==b.hide&&(b.hide=function(a){a.hide()}),_transitions[a]=b}function fingerprint(a){if(null==a||void 0==a)return 0;var b,c,d,e=a.toString(),f=0;if(0==e.length)return f;for(b=0,d=e.length;d>b;b++)c=e.charCodeAt(b),f=(f<<5)-f+c,f|=0;return f}function log(a,b,c){null==a&&(a=$("body")),a.trigger("log.ic",b,c,a)}function uuid(){return _UUID++}function icSelectorFor(a){return"[ic-id='"+getIntercoolerId(a)+"']"}function findById(a){return $("#"+a)}function parseInterval(a){return log(null,"POLL: Parsing interval string "+a,"DEBUG"),"null"==a||"false"==a||""==a?null:a.lastIndexOf("ms")==a.length-2?parseInt(a.substr(0,a.length-2)):a.lastIndexOf("s")==a.length-1?1e3*parseInt(a.substr(0,a.length-1)):1e3}function initScrollHandler(){null==_scrollHandler&&(_scrollHandler=function(){$("[ic-trigger-on='scrolled-into-view']").each(function(){isScrolledIntoView($(this))&&1!=$(this).data("ic-scrolled-into-view-loaded")&&($(this).data("ic-scrolled-into-view-loaded",!0),fireICRequest($(this)))})},$(window).scroll(_scrollHandler))}function getTarget(a){return a.attr("ic-target")&&0!=a.attr("ic-target").indexOf("this.")?$(a.attr("ic-target")):a}function processHeaders(elt,xhr,pop){elt.trigger("beforeHeaders.ic",elt,xhr);var target=null;if(xhr.getResponseHeader("X-IC-Refresh")){var pathsToRefresh=xhr.getResponseHeader("X-IC-Refresh").split(",");log(elt,"IC HEADER: refreshing "+pathsToRefresh,"DEBUG"),$.each(pathsToRefresh,function(a,b){refreshDependencies(b.replace(/ /g,""),elt)})}if(xhr.getResponseHeader("X-IC-Script")&&(log(elt,"IC HEADER: evaling "+xhr.getResponseHeader("X-IC-Script"),"DEBUG"),eval(xhr.getResponseHeader("X-IC-Script"))),xhr.getResponseHeader("X-IC-Redirect")&&(log(elt,"IC HEADER: redirecting to "+xhr.getResponseHeader("X-IC-Redirect"),"DEBUG"),window.location=xhr.getResponseHeader("X-IC-Redirect")),"true"==xhr.getResponseHeader("X-IC-CancelPolling")&&cancelPolling(elt),xhr.getResponseHeader("X-IC-Open")&&(log(elt,"IC HEADER: opening "+xhr.getResponseHeader("X-IC-Open"),"DEBUG"),window.open(xhr.getResponseHeader("X-IC-Open"))),xhr.getResponseHeader("X-IC-SetLocation")&&1!=pop&&(log(elt,"IC HEADER: pushing "+xhr.getResponseHeader("X-IC-SetLocation"),"DEBUG"),_historySupport.pushUrl(xhr.getResponseHeader("X-IC-SetLocation"),elt)),xhr.getResponseHeader("X-IC-Transition")&&(log(elt,"IC HEADER: setting transition to "+xhr.getResponseHeader("X-IC-Transition"),"DEBUG"),target=getTarget(elt),target.data("ic-tmp-transition",xhr.getResponseHeader("X-IC-Transition"))),xhr.getResponseHeader("X-IC-Remove")&&elt){target=getTarget(elt),log(elt,"IC REMOVE","DEBUG");var transition=getTransition(elt,target);transition.remove(target)}return elt.trigger("afterHeaders.ic",elt,xhr),!0}function handleTestResponse(a,b,c){var d=findIndicator(a),e=getTransition(d,d);d.length>0&&e.show(d);var f={};c&&c.headers&&(f=c.headers);var g="";c&&("string"==typeof c||c instanceof String?g=c:("string"==typeof c.body||c.body instanceof String)&&(g=c.body)),processHeaders(a,{getResponseHeader:function(a){return f[a]}}),b(g,"",a),d.length>0&&e.hide(d)}function beforeRequest(a){a.addClass("disabled")}function afterRequest(a){a.removeClass("disabled")}function replaceOrAddMethod(a,b){var c=/(&|^)_method=[^&]*/,d="&_method="+b;return c.test(a)?a.replace(c,d):a+"&"+d}function handleRemoteRequest(a,b,c,d,e){d=replaceOrAddMethod(d,b);for(var f=d.indexOf("&ic-handle-pop=true")>=0,g=0,h=_urlHandlers.length;h>g;g++){var i=_urlHandlers[g],j=null;if(null==i.url||new RegExp(i.url.replace(/\*/g,".*").replace(/\//g,"\\/")).test(c))return"GET"==b&&i.get&&(i.get&&(j=i.get(c,parseParams(d))),handleTestResponse(a,e,j)),"POST"==b&&(i.post&&(j=i.post(c,parseParams(d))),handleTestResponse(a,e,j)),"PUT"==b&&(i.put&&(j=i.put(c,parseParams(d))),handleTestResponse(a,e,j)),"DELETE"==b&&(i.delete&&(j=i.delete(c,parseParams(d))),handleTestResponse(a,e,j)),void 0}beforeRequest(a);var k=findIndicator(a),l=getTransition(k,k);k.length>0&&l.show(k),_remote.ajax({type:b,url:c,data:d,dataType:"text",headers:{Accept:"text/html-partial, */*; q=0.9"},beforeSend:function(b,c){a.trigger("beforeSend.ic",a,d,c,b)},success:function(b,c,d){a.trigger("success.ic",a,b,c,d);var g=getTarget(a);g.data("ic-tmp-transition",a.attr("ic-transition")),processHeaders(a,d,f)&&e(b,c,a,d),g.data("ic-tmp-transition",null)},error:function(b,c,d){a.trigger("error.ic",a,c,d,b),log(a,"An error occurred: "+d,"ERROR")},complete:function(b,c){a.trigger("complete.ic",a,d,c,b),k.length>0&&l.hide(k),afterRequest(a)}})}function findIndicator(a){var b=null;if($(a).attr("ic-indicator"))b=$($(a).attr("ic-indicator")).first();else if(b=$(a).find(".ic-indicator").first(),0==b.length){var c=$(a).closest("[ic-indicator]");c.length>0&&(b=$(c.first().attr("ic-indicator")).first())}return b}function parseParams(a){var b,c=/([^&=]+)=?([^&]*)/g,d=function(a){return decodeURIComponent(a.replace(/\+/g," "))},e={};if(a)for("?"==a.substr(0,1)&&(a=a.substr(1));b=c.exec(a);){var f=d(b[1]),g=d(b[2]);void 0!==e[f]?($.isArray(e[f])||(e[f]=[e[f]]),e[f].push(g)):e[f]=g}return e}function processIncludes(a){var b="";return $(a).each(function(){b+="&"+$(this).serialize()}),b}function getParametersForElement(a){var b=getTarget(a),c="ic-request=true";return c+=a.closest("form").length>0?"&"+a.closest("form").serialize():"&"+a.serialize(),a.attr("id")&&(c+="&ic-element-id="+a.attr("id")),a.attr("name")&&(c+="&ic-element-name="+a.attr("name")),b.attr("ic-id")&&(c+="&ic-id="+b.attr("ic-id")),b.attr("ic-last-refresh")&&(c+="&ic-last-refresh="+b.attr("ic-last-refresh")),b.attr("ic-fingerprint")&&(c+="&ic-fingerprint="+b.attr("ic-fingerprint")),a.attr("ic-include")&&(c+=processIncludes(a.attr("ic-include"))),log(a,"PARAMS: Returning parameters "+c+" for "+a,"DEBUG"),c}function maybeSetIntercoolerInfo(a){var b=getTarget(a);log(a,"Setting IC info","DEBUG"),getIntercoolerId(b),maybeSetIntercoolerMetadata(b)}function updateIntercoolerMetaData(a){a.attr("ic-fingerprint",fingerprint(a.html())),a.attr("ic-last-refresh",(new Date).getTime())}function maybeSetIntercoolerMetadata(a){a.attr("ic-fingerprint")||updateIntercoolerMetaData(a)}function getIntercoolerId(a){return a.attr("ic-id")||a.attr("ic-id",uuid()),a.attr("ic-id")}function processNodes(a){processMacros(a),processSources(a),processPolling(a),processTriggerOn(a)}function processSources(a){$(a).is("[ic-src]")&&maybeSetIntercoolerInfo($(a)),$(a).find("[ic-src]").each(function(){maybeSetIntercoolerInfo($(this))})}function startPolling(a){if(null==a.data("ic-poll-interval-id")){var b=parseInterval(a.attr("ic-poll"));if(null!=b){var c=icSelectorFor(a);log(a,"POLL: Starting poll for element "+c,"DEBUG");var d=setInterval(function(){var b=$(c);a.trigger("onPoll.ic",b),0==b.length?(log(a,"POLL: Clearing poll for element "+c,"DEBUG"),clearTimeout(d)):fireICRequest(b)},b);a.data("ic-poll-interval-id",d)}}}function cancelPolling(a){null!=a.data("ic-poll-interval-id")&&clearTimeout(a.data("ic-poll-interval-id"))}function processPolling(a){$(a).is("[ic-poll]")&&(maybeSetIntercoolerInfo($(a)),startPolling(a)),$(a).find("[ic-poll]").each(function(){maybeSetIntercoolerInfo($(this)),startPolling($(this))})}function refreshDependencies(a,b){log(b,"Refreshing Dependencies for "+a,"DEBUG"),$("[ic-src]").each(function(){var c=!1;"GET"==verbFor($(this))&&"ignore"!=$(this).attr("ic-deps")&&(isDependent(a,$(this).attr("ic-src"))?(null==b||$(b)[0]!=$(this)[0])&&(fireICRequest($(this)),c=!0):(isDependent(a,$(this).attr("ic-deps"))||"*"==$(this).attr("ic-deps"))&&(null==b||$(b)[0]!=$(this)[0])&&(fireICRequest($(this)),c=!0)),c||log($(this),"Does not depend on "+a,"DEBUG")})}function isDependent(a,b){return a&&b&&(0==b.indexOf(a)||0==a.indexOf(b))}function verbFor(a){return a.attr("ic-verb")?a.attr("ic-verb").toUpperCase():"GET"}function eventFor(a,b){return"default"==a?$(b).is("button")?"click":$(b).is("form")?"submit":$(b).is(":input")?"change":"click":a}function preventDefault(a){return a.is("form")||a.is(":submit")&&1==a.closest("form").length}function handleTriggerOn(a){$(a).attr("ic-trigger-on")&&("load"==$(a).attr("ic-trigger-on")?fireICRequest(a):"scrolled-into-view"==$(a).attr("ic-trigger-on")?(initScrollHandler(),setTimeout(function(){$(window).trigger("scroll")},100)):$(a).on(eventFor($(a).attr("ic-trigger-on"),$(a)),function(b){return fireICRequest($(a)),preventDefault(a)?(b.preventDefault(),!1):!0}))}function processTriggerOn(a){handleTriggerOn(a),$(a).find("[ic-trigger-on]").each(function(){handleTriggerOn($(this))})}function processMacros(a){$.each(_MACROS,function(b,c){$(a).is("["+c+"]")&&processMacro(c,$(a)),$(a).find("["+c+"]").each(function(){processMacro(c,$(this))})})}function processMacro(a,b){"ic-post-to"==a&&(setIfAbsent(b,"ic-src",b.attr("ic-post-to")),setIfAbsent(b,"ic-verb","POST"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),"ic-put-to"==a&&(setIfAbsent(b,"ic-src",b.attr("ic-put-to")),setIfAbsent(b,"ic-verb","PUT"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),"ic-get-from"==a&&(setIfAbsent(b,"ic-src",b.attr("ic-get-from")),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore")),"ic-delete-from"==a&&(setIfAbsent(b,"ic-src",b.attr("ic-delete-from")),setIfAbsent(b,"ic-verb","DELETE"),setIfAbsent(b,"ic-trigger-on","default"),setIfAbsent(b,"ic-deps","ignore"));var c=null,d=null;if("ic-style-src"==a){c=b.attr("ic-style-src").split(":");var e=c[0];d=c[1],setIfAbsent(b,"ic-src",d),setIfAbsent(b,"ic-target","this.style."+e)}if("ic-attr-src"==a){c=b.attr("ic-attr-src").split(":");var f=c[0];d=c[1],setIfAbsent(b,"ic-src",d),setIfAbsent(b,"ic-target","this."+f)}"ic-prepend-from"==a&&(setIfAbsent(b,"ic-src",b.attr("ic-prepend-from")),setIfAbsent(b,"ic-transition","prepend")),"ic-append-from"==a&&(setIfAbsent(b,"ic-src",b.attr("ic-append-from")),setIfAbsent(b,"ic-transition","append"))}function setIfAbsent(a,b,c){null==a.attr(b)&&a.attr(b,c)}function isScrolledIntoView(a){var b=$(window).scrollTop(),c=b+$(window).height(),d=$(a).offset().top,e=d+$(a).height();return e>=b&&c>=d&&c>=e&&d>=b}function getTransition(a,b){var c=null;return a.attr("ic-transition")&&(c=_transitions[a.attr("ic-transition")]),b.attr("ic-transition")&&(c=_transitions[b.attr("ic-transition")]),b.data("ic-tmp-transition")&&(c=_transitions[b.data("ic-tmp-transition")]),null==c&&(c=_transitions[_defaultTransition]),null==c&&(c=_transitions.none),c}function processICResponse(a,b){if(a&&/\S/.test(a)){log(b,"IC RESPONSE: Received: "+a,"DEBUG");var c=getTarget(b),d=$("<div></div>").html(a);if(processMacros(d),fingerprint(d.html())!=c.attr("ic-fingerprint")||"true"==c.attr("ic-always-update")){var e=getTransition(b,c);e.newContent(c,a,!1,function(){processNodes(c),updateIntercoolerMetaData(c)})}d.remove()}}function getStyleTarget(a){return a.attr("ic-target")&&0==a.attr("ic-target").indexOf("this.style.")?a.attr("ic-target").substr(11):null}function getAttrTarget(a){return a.attr("ic-target")&&0==a.attr("ic-target").indexOf("this.")?a.attr("ic-target").substr(5):null}function fireICRequest(a){var b=getStyleTarget(a),c=b?null:getAttrTarget(a);if(a.attr("ic-src")){var d=verbFor(a);handleRemoteRequest(a,d,a.attr("ic-src"),getParametersForElement(a),function(e){b?a.css(b,e):c?a.attr(c,e):(processICResponse(e,a),"GET"!=d&&refreshDependencies(a.attr("ic-src"),a))})}}var _MACROS=["ic-get-from","ic-post-to","ic-put-to","ic-delete-from","ic-style-src","ic-attr-src","ic-prepend-from","ic-append-from"],_remote=$,_urlHandlers=[],_scrollHandler=null,_UUID=1,_transitions={},_defaultTransition="fadeFast";_defineTransition("none",{}),_defineTransition("fadeFast",{newContent:function(a,b,c,d){a.fadeOut("fast",function(){a.html(b),d(),a.fadeIn("fast")})},remove:function(a){a.fadeOut("fast",function(){a.remove()})},show:function(a){a.fadeIn("fast")},hide:function(a){a.fadeOut("fast")}}),_defineTransition("prepend",{newContent:function(a,b,c,d){var e=$(b);if(e.hide(),a.prepend(e),d(),e.fadeIn(),a.attr("ic-limit-children")){var f=parseInt(a.attr("ic-limit-children"));a.children().length>f&&a.children().slice(f,a.children().length).remove()}}}),_defineTransition("append",{newContent:function(a,b,c,d){var e=$(b);if(e.hide(),a.append(e),d(),e.fadeIn(),a.attr("ic-limit-children")){var f=parseInt(a.attr("ic-limit-children"));a.children().length>f&&a.children().slice(0,a.children().length-f).remove()}}});var _historySupport={stateCache:null,popping:!1,getRestorationURL:function(a){return a.attr("ic-restore-from")?a.attr("ic-restore-from"):window.location.pathname+window.location.search+window.location.hash},onPageLoad:function(){if(_historySupport.stateCache={"ic-setlocation":!0,"restore-from":window.location.pathname+window.location.search+window.location.hash,timestamp:(new Date).getTime()},null==window.onpopstate||1!=window.onpopstate["ic-on-pop-state-handler"]){var a=window.onpopstate;window.onpopstate=function(b){_historySupport.handlePop(b)||a&&a(b)},window.onpopstate["ic-on-pop-state-handler"]=!0}},pushUrl:function(a,b){log(b,"IC HISTORY: pushing location "+a,"DEBUG");var c=getTarget(b),d=c.attr("id");if(null==d)return log(b,"To support history for a given element, you must have a valid id attribute on the element","ERROR"),void 0;_historySupport.initHistory(b);var e={"ic-setlocation":!0,"id-to-restore":d.toString(),"restore-from":a,timestamp:(new Date).getTime()};b.trigger("pushUrl.ic",c,e),window.history.pushState(e,"",a)},initHistory:function(a){if(_historySupport.stateCache){var b=getTarget(a),c=b.attr("id");_historySupport.stateCache["id-to-restore"]=c.toString(),window.history.replaceState(_historySupport.stateCache,"",_historySupport.stateCache["restore-from"]),_historySupport.stateCache=null}},handlePop:function(a){var b=a.state;if(b&&b["ic-setlocation"]){var c=findById(b["id-to-restore"]),d=getParametersForElement(c);return d+="&ic-handle-pop=true",handleRemoteRequest(c,"GET",b["restore-from"],d,function(a){c.trigger("handlePop.ic",c,a),processICResponse(a,c)}),!0}return!1}};return $(function(){processNodes("body"),_historySupport.onPageLoad()}),{refresh:function(a){return"string"==typeof a||a instanceof String?refreshDependencies(a):fireICRequest(a),Intercooler},defaultTransition:function(a){_defaultTransition=a},defineTransition:function(a,b){_defineTransition(a,b)},addURLHandler:function(a){if(!a.url)throw"Handlers must include a URL pattern";return _urlHandlers.push(a),Intercooler},setRemote:function(a){return _remote=a,Intercooler}}}();