semantic-ui-api
Advanced tools
Comparing version 1.12.3 to 2.0.2
584
api.js
/*! | ||
* # Semantic UI 1.12.3 - API | ||
* # Semantic UI 2.0.2 - API | ||
* http://github.com/semantic-org/semantic-ui/ | ||
* | ||
* | ||
* Copyright 2014 Contributors | ||
* Copyright 2015 Contributors | ||
* Released under the MIT license | ||
@@ -66,6 +66,7 @@ * http://opensource.org/licenses/MIT | ||
data, | ||
requestStartTime, | ||
// standard module | ||
element = this, | ||
context = $context.get(), | ||
context = $context[0], | ||
instance = $module.data(moduleNamespace), | ||
@@ -78,17 +79,4 @@ module | ||
initialize: function() { | ||
var | ||
triggerEvent = module.get.event() | ||
; | ||
// bind events | ||
if(!methodInvoked) { | ||
if( triggerEvent ) { | ||
module.debug('Attaching API events to element', triggerEvent); | ||
$module | ||
.on(triggerEvent + eventNamespace, module.event.trigger) | ||
; | ||
} | ||
else if(settings.on == 'now') { | ||
module.debug('Querying API now', triggerEvent); | ||
module.query(); | ||
} | ||
module.bind.events(); | ||
} | ||
@@ -114,2 +102,61 @@ module.instantiate(); | ||
bind: { | ||
events: function() { | ||
var | ||
triggerEvent = module.get.event() | ||
; | ||
if( triggerEvent ) { | ||
module.verbose('Attaching API events to element', triggerEvent); | ||
$module | ||
.on(triggerEvent + eventNamespace, module.event.trigger) | ||
; | ||
} | ||
else if(settings.on == 'now') { | ||
module.debug('Querying API now', triggerEvent); | ||
module.query(); | ||
} | ||
} | ||
}, | ||
read: { | ||
cachedResponse: function(url) { | ||
var | ||
response | ||
; | ||
if(window.Storage === undefined) { | ||
module.error(error.noStorage); | ||
return; | ||
} | ||
response = sessionStorage.getItem(url); | ||
module.debug('Using cached response', url, response); | ||
if(response !== undefined) { | ||
try { | ||
response = JSON.parse(response); | ||
} | ||
catch(e) { | ||
// didnt store object | ||
} | ||
return response; | ||
} | ||
return false; | ||
} | ||
}, | ||
write: { | ||
cachedResponse: function(url, response) { | ||
if(response && response === '') { | ||
module.debug('Response empty, not caching', response); | ||
return; | ||
} | ||
if(window.Storage === undefined) { | ||
module.error(error.noStorage); | ||
return; | ||
} | ||
if( $.isPlainObject(response) ) { | ||
response = JSON.stringify(response); | ||
} | ||
sessionStorage.setItem(url, response); | ||
module.verbose('Storing cached response for url', url, response); | ||
} | ||
}, | ||
query: function() { | ||
@@ -121,6 +168,12 @@ | ||
} | ||
// determine if an api event already occurred | ||
if(module.is.loading() && settings.throttle === 0 ) { | ||
module.debug('Cancelling request, previous request is still pending'); | ||
return; | ||
if(module.is.loading()) { | ||
if(settings.interruptRequests) { | ||
module.debug('Interrupting previous request'); | ||
module.abort(); | ||
} | ||
else { | ||
module.debug('Cancelling request, previous request is still pending'); | ||
return; | ||
} | ||
} | ||
@@ -134,13 +187,8 @@ | ||
// Add form content | ||
if(settings.serializeForm !== false || $context.is('form')) { | ||
if(settings.serializeForm == 'json') { | ||
$.extend(true, settings.data, module.get.formData()); | ||
} | ||
else { | ||
settings.data = module.get.formData(); | ||
} | ||
if(settings.serializeForm) { | ||
settings.data = module.add.formData(settings.data); | ||
} | ||
// call beforesend and get any settings changes | ||
requestSettings = module.get.settings(); | ||
requestSettings = module.get.settings(); | ||
@@ -157,27 +205,18 @@ // check if before send cancelled request | ||
if(settings.url) { | ||
// override with url if specified | ||
module.debug('Using specified url', url); | ||
url = module.add.urlData( settings.url ); | ||
// get url | ||
url = module.get.templatedURL(); | ||
if(!url && !module.is.mocked()) { | ||
module.error(error.missingURL); | ||
return; | ||
} | ||
else { | ||
// otherwise find url from api endpoints | ||
url = module.add.urlData( module.get.templateURL() ); | ||
module.debug('Added URL Data to url', url); | ||
} | ||
// exit conditions reached, missing url parameters | ||
if( !url ) { | ||
if( module.is.form() ) { | ||
url = $module.attr('action') || ''; | ||
module.debug('No url or action specified, defaulting to form action', url); | ||
} | ||
else { | ||
module.error(error.missingURL, settings.action); | ||
return; | ||
} | ||
// replace variables | ||
url = module.add.urlData( url ); | ||
// missing url parameters | ||
if( !url && !module.is.mocked()) { | ||
return; | ||
} | ||
// add loading state | ||
module.set.loading(); | ||
@@ -196,18 +235,32 @@ // look for jQuery ajax parameters in settings | ||
module.debug('Querying URL', ajaxSettings.url); | ||
module.debug('Sending data', data, ajaxSettings.method); | ||
module.verbose('Using AJAX settings', ajaxSettings); | ||
if( module.is.loading() ) { | ||
// throttle additional requests | ||
module.timer = setTimeout(function() { | ||
module.request = module.create.request(); | ||
module.xhr = module.create.xhr(); | ||
settings.onRequest.call(context, module.request, module.xhr); | ||
}, settings.throttle); | ||
if(settings.cache === 'local' && module.read.cachedResponse(url)) { | ||
module.debug('Response returned from local cache'); | ||
module.request = module.create.request(); | ||
module.request.resolveWith(context, [ module.read.cachedResponse(url) ]); | ||
return; | ||
} | ||
if( !settings.throttle ) { | ||
module.debug('Sending request', data, ajaxSettings.method); | ||
module.send.request(); | ||
} | ||
else { | ||
// immediately on first request | ||
module.request = module.create.request(); | ||
module.xhr = module.create.xhr(); | ||
settings.onRequest.call(context, module.request, module.xhr); | ||
if(!settings.throttleFirstRequest && !module.timer) { | ||
module.debug('Sending request', data, ajaxSettings.method); | ||
module.send.request(); | ||
module.timer = setTimeout(function(){}, settings.throttle); | ||
} | ||
else { | ||
module.debug('Throttling request', settings.throttle); | ||
clearTimeout(module.timer); | ||
module.timer = setTimeout(function() { | ||
if(module.timer) { | ||
delete module.timer; | ||
} | ||
module.debug('Sending throttled request', data, ajaxSettings.method); | ||
module.send.request(); | ||
}, settings.throttle); | ||
} | ||
} | ||
@@ -217,6 +270,5 @@ | ||
is: { | ||
disabled: function() { | ||
return ($module.filter(settings.filter).length > 0); | ||
return ($module.filter(selector.disabled).length > 0); | ||
}, | ||
@@ -226,2 +278,5 @@ form: function() { | ||
}, | ||
mocked: function() { | ||
return (settings.mockResponse || settings.mockResponseAsync); | ||
}, | ||
input: function() { | ||
@@ -232,2 +287,27 @@ return $module.is('input'); | ||
return (module.request && module.request.state() == 'pending'); | ||
}, | ||
abortedRequest: function(xhr) { | ||
if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) { | ||
module.verbose('XHR request determined to be aborted'); | ||
return true; | ||
} | ||
else { | ||
module.verbose('XHR request was not aborted'); | ||
return false; | ||
} | ||
}, | ||
validResponse: function(response) { | ||
if( settings.dataType !== 'json' || !$.isFunction(settings.successTest) ) { | ||
module.verbose('Response is not JSON, skipping validation', settings.successTest, response); | ||
return true; | ||
} | ||
module.debug('Checking JSON returned success', settings.successTest, response); | ||
if( settings.successTest(response) ) { | ||
module.debug('Response passed success test', response); | ||
return true; | ||
} | ||
else { | ||
module.debug('Response failed success test', response); | ||
return false; | ||
} | ||
} | ||
@@ -324,5 +404,47 @@ }, | ||
return url; | ||
}, | ||
formData: function(data) { | ||
var | ||
canSerialize = ($.fn.serializeObject !== undefined), | ||
formData = (canSerialize) | ||
? $form.serializeObject() | ||
: $form.serialize(), | ||
hasOtherData | ||
; | ||
data = data || settings.data; | ||
hasOtherData = $.isPlainObject(data); | ||
if(hasOtherData) { | ||
if(canSerialize) { | ||
module.debug('Extending existing data with form data', data, formData); | ||
data = $.extend(true, {}, data, formData); | ||
} | ||
else { | ||
module.error(error.missingSerialize); | ||
module.debug('Cant extend data. Replacing data with form data', data, formData); | ||
data = formData; | ||
} | ||
} | ||
else { | ||
module.debug('Adding form data', formData); | ||
data = formData; | ||
} | ||
return data; | ||
} | ||
}, | ||
send: { | ||
request: function() { | ||
module.set.loading(); | ||
module.request = module.create.request(); | ||
if( module.is.mocked() ) { | ||
module.mockedXHR = module.create.mockedXHR(); | ||
} | ||
else { | ||
module.xhr = module.create.xhr(); | ||
} | ||
settings.onRequest.call(context, module.request, module.xhr); | ||
} | ||
}, | ||
event: { | ||
@@ -339,7 +461,10 @@ trigger: function(event) { | ||
}, | ||
done: function(response) { | ||
done: function(response, textStatus, xhr) { | ||
var | ||
context = this, | ||
elapsedTime = (new Date().getTime() - time), | ||
timeLeft = (settings.loadingDuration - elapsedTime) | ||
elapsedTime = (new Date().getTime() - requestStartTime), | ||
timeLeft = (settings.loadingDuration - elapsedTime), | ||
translatedResponse = ( $.isFunction(settings.onResponse) ) | ||
? settings.onResponse.call(context, $.extend(true, {}, response)) | ||
: false | ||
; | ||
@@ -350,4 +475,16 @@ timeLeft = (timeLeft > 0) | ||
; | ||
if(translatedResponse) { | ||
module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response); | ||
response = translatedResponse; | ||
} | ||
if(timeLeft > 0) { | ||
module.debug('Response completed early delaying state change by', timeLeft); | ||
} | ||
setTimeout(function() { | ||
module.request.resolveWith(context, [response]); | ||
if( module.is.validResponse(response) ) { | ||
module.request.resolveWith(context, [response]); | ||
} | ||
else { | ||
module.request.rejectWith(context, [xhr, 'invalid']); | ||
} | ||
}, timeLeft); | ||
@@ -358,3 +495,3 @@ }, | ||
context = this, | ||
elapsedTime = (new Date().getTime() - time), | ||
elapsedTime = (new Date().getTime() - requestStartTime), | ||
timeLeft = (settings.loadingDuration - elapsedTime) | ||
@@ -366,9 +503,11 @@ ; | ||
; | ||
// page triggers abort on navigation, dont show error | ||
if(timeLeft > 0) { | ||
module.debug('Response completed early delaying state change by', timeLeft); | ||
} | ||
setTimeout(function() { | ||
if(status !== 'abort') { | ||
module.request.rejectWith(context, [xhr, status, httpMessage]); | ||
if( module.is.abortedRequest(xhr) ) { | ||
module.request.rejectWith(context, [xhr, 'aborted', httpMessage]); | ||
} | ||
else { | ||
module.reset(); | ||
module.request.rejectWith(context, [xhr, 'error', status, httpMessage]); | ||
} | ||
@@ -384,65 +523,47 @@ }, timeLeft); | ||
done: function(response) { | ||
module.debug('API Response Received', response); | ||
if(settings.dataType == 'json') { | ||
if( $.isFunction(settings.successTest) ) { | ||
module.debug('Checking JSON returned success', settings.successTest, response); | ||
if( settings.successTest(response) ) { | ||
settings.onSuccess.call(context, response, $module); | ||
} | ||
else { | ||
module.debug('JSON test specified by user and response failed', response); | ||
settings.onFailure.call(context, response, $module); | ||
} | ||
} | ||
else { | ||
settings.onSuccess.call(context, response, $module); | ||
} | ||
module.debug('Successful API Response', response); | ||
if(settings.cache === 'local' && url) { | ||
module.write.cachedResponse(url, response); | ||
module.debug('Saving server response locally', module.cache); | ||
} | ||
else { | ||
settings.onSuccess.call(context, response, $module); | ||
} | ||
settings.onSuccess.call(context, response, $module); | ||
}, | ||
error: function(xhr, status, httpMessage) { | ||
fail: function(xhr, status, httpMessage) { | ||
var | ||
errorMessage = (settings.error[status] !== undefined) | ||
? settings.error[status] | ||
: httpMessage, | ||
response | ||
// pull response from xhr if available | ||
response = $.isPlainObject(xhr) | ||
? (xhr.responseText) | ||
: false, | ||
errorMessage = ($.isPlainObject(response) && response.error !== undefined) | ||
? response.error // use json error message | ||
: (settings.error[status] !== undefined) // use server error message | ||
? settings.error[status] | ||
: httpMessage | ||
; | ||
// let em know unless request aborted | ||
if(xhr !== undefined) { | ||
// readyState 4 = done, anything less is not really sent | ||
if(xhr.readyState !== undefined && xhr.readyState == 4) { | ||
if(status == 'aborted') { | ||
module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage); | ||
settings.onAbort.call(context, status, $module); | ||
} | ||
else if(status == 'invalid') { | ||
module.debug('JSON did not pass success test. A server-side error has most likely occurred', response); | ||
} | ||
else if(status == 'error') { | ||
// if http status code returned and json returned error, look for it | ||
if(xhr !== undefined) { | ||
module.debug('XHR produced a server error', status, httpMessage); | ||
// make sure we have an error to display to console | ||
if( xhr.status != 200 && httpMessage !== undefined && httpMessage !== '') { | ||
module.error(error.statusMessage + httpMessage, ajaxSettings.url); | ||
} | ||
else { | ||
if(status == 'error' && settings.dataType == 'json') { | ||
try { | ||
response = $.parseJSON(xhr.responseText); | ||
if(response && response.error !== undefined) { | ||
errorMessage = response.error; | ||
} | ||
} | ||
catch(e) { | ||
module.error(error.JSONParse); | ||
} | ||
} | ||
} | ||
module.remove.loading(); | ||
module.set.error(); | ||
// show error state only for duration specified in settings | ||
if(settings.errorDuration) { | ||
setTimeout(module.remove.error, settings.errorDuration); | ||
} | ||
module.debug('API Request error:', errorMessage); | ||
settings.onError.call(context, errorMessage, $module); | ||
} | ||
else { | ||
settings.onAbort.call(context, errorMessage, $module); | ||
module.debug('Request Aborted (Most likely caused by page change or CORS Policy)', status, httpMessage); | ||
} | ||
} | ||
if(settings.errorDuration && status !== 'aborted') { | ||
module.debug('Adding error state'); | ||
module.set.error(); | ||
setTimeout(module.remove.error, settings.errorDuration); | ||
} | ||
module.debug('API Request failed', errorMessage, xhr); | ||
settings.onFailure.call(context, response, $module); | ||
} | ||
@@ -453,11 +574,64 @@ } | ||
create: { | ||
request: function() { | ||
// api request promise | ||
return $.Deferred() | ||
.always(module.event.request.complete) | ||
.done(module.event.request.done) | ||
.fail(module.event.request.error) | ||
.fail(module.event.request.fail) | ||
; | ||
}, | ||
mockedXHR: function () { | ||
var | ||
// xhr does not simulate these properties of xhr but must return them | ||
textStatus = false, | ||
status = false, | ||
httpMessage = false, | ||
asyncCallback, | ||
response, | ||
mockedXHR | ||
; | ||
mockedXHR = $.Deferred() | ||
.always(module.event.xhr.complete) | ||
.done(module.event.xhr.done) | ||
.fail(module.event.xhr.fail) | ||
; | ||
if(settings.mockResponse) { | ||
if( $.isFunction(settings.mockResponse) ) { | ||
module.debug('Using mocked callback returning response', settings.mockResponse); | ||
response = settings.mockResponse.call(context, settings); | ||
} | ||
else { | ||
module.debug('Using specified response', settings.mockResponse); | ||
response = settings.mockResponse; | ||
} | ||
// simulating response | ||
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); | ||
} | ||
else if( $.isFunction(settings.mockResponseAsync) ) { | ||
asyncCallback = function(response) { | ||
module.debug('Async callback returned response', response); | ||
if(response) { | ||
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); | ||
} | ||
else { | ||
mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]); | ||
} | ||
}; | ||
module.debug('Using async mocked response', settings.mockResponseAsync); | ||
settings.mockResponseAsync.call(context, settings, asyncCallback); | ||
} | ||
return mockedXHR; | ||
}, | ||
xhr: function() { | ||
return $.ajax(ajaxSettings) | ||
var | ||
xhr | ||
; | ||
// ajax request promise | ||
xhr = $.ajax(ajaxSettings) | ||
.always(module.event.xhr.always) | ||
@@ -467,2 +641,4 @@ .done(module.event.xhr.done) | ||
; | ||
module.verbose('Created server request', xhr); | ||
return xhr; | ||
} | ||
@@ -479,2 +655,3 @@ }, | ||
$context.addClass(className.loading); | ||
requestStartTime = new Date().getTime(); | ||
} | ||
@@ -505,3 +682,3 @@ }, | ||
; | ||
runSettings = settings.beforeSend.call($module, settings); | ||
runSettings = settings.beforeSend.call(context, settings); | ||
if(runSettings) { | ||
@@ -574,31 +751,21 @@ if(runSettings.success !== undefined) { | ||
}, | ||
formData: function() { | ||
var | ||
formData | ||
; | ||
if($module.serializeObject !== undefined) { | ||
formData = $form.serializeObject(); | ||
templatedURL: function(action) { | ||
action = action || $module.data(metadata.action) || settings.action || false; | ||
url = $module.data(metadata.url) || settings.url || false; | ||
if(url) { | ||
module.debug('Using specified url', url); | ||
return url; | ||
} | ||
else { | ||
module.error(error.missingSerialize); | ||
formData = $form.serialize(); | ||
} | ||
module.debug('Retrieved form data', formData); | ||
return formData; | ||
}, | ||
templateURL: function(action) { | ||
var | ||
url | ||
; | ||
action = action || $module.data(metadata.action) || settings.action || false; | ||
if(action) { | ||
module.debug('Looking up url for action', action, settings.api); | ||
if(settings.api[action] !== undefined) { | ||
url = settings.api[action]; | ||
module.debug('Found template url', url); | ||
} | ||
else if( !module.is.form() ) { | ||
if(settings.api[action] === undefined && !module.is.mocked()) { | ||
module.error(error.missingAction, settings.action, settings.api); | ||
return; | ||
} | ||
url = settings.api[action]; | ||
} | ||
else if( module.is.form() ) { | ||
url = $module.attr('action') || false; | ||
module.debug('No url or action specified, defaulting to form action', url); | ||
} | ||
return url; | ||
@@ -615,3 +782,2 @@ } | ||
xhr.abort(); | ||
module.request.rejectWith(settings.apiSettings); | ||
} | ||
@@ -695,3 +861,3 @@ }, | ||
clearTimeout(module.performance.timer); | ||
module.performance.timer = setTimeout(module.performance.display, 100); | ||
module.performance.timer = setTimeout(module.performance.display, 500); | ||
}, | ||
@@ -806,45 +972,84 @@ display: function() { | ||
name : 'API', | ||
namespace : 'api', | ||
name : 'API', | ||
namespace : 'api', | ||
debug : true, | ||
verbose : false, | ||
performance : true, | ||
debug : true, | ||
verbose : false, | ||
performance : true, | ||
// object containing all templates endpoints | ||
api : {}, | ||
// whether to cache responses | ||
cache : true, | ||
// whether new requests should abort previous requests | ||
interruptRequests : true, | ||
// event binding | ||
on : 'auto', | ||
filter : '.disabled', | ||
stateContext : false, | ||
on : 'auto', | ||
// state | ||
loadingDuration : 0, | ||
errorDuration : 2000, | ||
// context for applying state classes | ||
stateContext : false, | ||
// templating | ||
action : false, | ||
url : false, | ||
base : '', | ||
// duration for loading state | ||
loadingDuration : 0, | ||
// data | ||
urlData : {}, | ||
// duration for error state | ||
errorDuration : 2000, | ||
// ui | ||
defaultData : true, | ||
serializeForm : false, | ||
throttle : 0, | ||
// API action to use | ||
action : false, | ||
// jQ ajax | ||
method : 'get', | ||
data : {}, | ||
dataType : 'json', | ||
// templated URL to use | ||
url : false, | ||
// callbacks | ||
// base URL to apply to all endpoints | ||
base : '', | ||
// data that will | ||
urlData : {}, | ||
// whether to add default data to url data | ||
defaultData : true, | ||
// whether to serialize closest form | ||
serializeForm : false, | ||
// how long to wait before request should occur | ||
throttle : 0, | ||
// whether to throttle first request or only repeated | ||
throttleFirstRequest : true, | ||
// standard ajax settings | ||
method : 'get', | ||
data : {}, | ||
dataType : 'json', | ||
// mock response | ||
mockResponse : false, | ||
mockResponseAsync : false, | ||
// callbacks before request | ||
beforeSend : function(settings) { return settings; }, | ||
beforeXHR : function(xhr) {}, | ||
onRequest : function(promise, xhr) {}, | ||
onRequest : function(promise, xhr) {}, | ||
// after request | ||
onResponse : false, // function(response) { }, | ||
// response was successful, if JSON passed validation | ||
onSuccess : function(response, $module) {}, | ||
// request finished without aborting | ||
onComplete : function(response, $module) {}, | ||
onFailure : function(errorMessage, $module) {}, | ||
// failed JSON success test | ||
onFailure : function(response, $module) {}, | ||
// server error | ||
onError : function(errorMessage, $module) {}, | ||
// request aborted | ||
onAbort : function(errorMessage, $module) {}, | ||
@@ -863,5 +1068,6 @@ | ||
missingAction : 'API action used but no url was defined', | ||
missingSerialize : 'Required dependency jquery-serialize-object missing, using basic serialize', | ||
missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object', | ||
missingURL : 'No URL specified for api event', | ||
noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.', | ||
noStorage : 'Caching respopnses locally requires session storage', | ||
parseError : 'There was an error parsing your request', | ||
@@ -874,4 +1080,4 @@ requiredParameter : 'Missing a required URL parameter: ', | ||
regExp : { | ||
required: /\{\$*[A-z0-9]+\}/g, | ||
optional: /\{\/\$*[A-z0-9]+\}/g, | ||
required : /\{\$*[A-z0-9]+\}/g, | ||
optional : /\{\/\$*[A-z0-9]+\}/g, | ||
}, | ||
@@ -885,7 +1091,9 @@ | ||
selector: { | ||
form: 'form' | ||
disabled : '.disabled', | ||
form : 'form' | ||
}, | ||
metadata: { | ||
action : 'action' | ||
action : 'action', | ||
url : 'url' | ||
} | ||
@@ -895,5 +1103,3 @@ }; | ||
$.api.settings.api = {}; | ||
})( jQuery, window , document ); | ||
})( jQuery, window , document ); |
/*! | ||
* # Semantic UI 1.12.3 - API | ||
* # Semantic UI 2.0.2 - API | ||
* http://github.com/semantic-org/semantic-ui/ | ||
* | ||
* | ||
* Copyright 2014 Contributors | ||
* Copyright 2015 Contributors | ||
* Released under the MIT license | ||
@@ -11,2 +11,2 @@ * http://opensource.org/licenses/MIT | ||
*/ | ||
!function(e,t,r,n){"use strict";e.api=e.fn.api=function(r){var o,a=e(e.isFunction(this)?t:this),i=a.selector||"",s=(new Date).getTime(),u=[],c=arguments[0],l="string"==typeof c,d=[].slice.call(arguments,1);return a.each(function(){var t,a,f,g,m,p=e.isPlainObject(r)?e.extend(!0,{},e.fn.api.settings,r):e.extend({},e.fn.api.settings),b=p.namespace,v=p.metadata,h=p.selector,y=p.error,q=p.className,x="."+b,A="module-"+b,D=e(this),P=D.closest(h.form),R=p.stateContext?e(p.stateContext):D,T=this,S=R.get(),j=D.data(A);m={initialize:function(){var e=m.get.event();l||(e?(m.debug("Attaching API events to element",e),D.on(e+x,m.event.trigger)):"now"==p.on&&(m.debug("Querying API now",e),m.query())),m.instantiate()},instantiate:function(){m.verbose("Storing instance of module",m),j=m,D.data(A,j)},destroy:function(){m.verbose("Destroying previous module for",T),D.removeData(A).off(x)},query:function(){if(m.is.disabled())return void m.debug("Element is disabled API request aborted");if(m.is.loading()&&0===p.throttle)return void m.debug("Cancelling request, previous request is still pending");if(p.defaultData&&e.extend(!0,p.urlData,m.get.defaultData()),(p.serializeForm!==!1||R.is("form"))&&("json"==p.serializeForm?e.extend(!0,p.data,m.get.formData()):p.data=m.get.formData()),a=m.get.settings(),a===!1)return m.cancelled=!0,void m.error(y.beforeSend);if(m.cancelled=!1,p.url?(m.debug("Using specified url",f),f=m.add.urlData(p.url)):(f=m.add.urlData(m.get.templateURL()),m.debug("Added URL Data to url",f)),!f){if(!m.is.form())return void m.error(y.missingURL,p.action);f=D.attr("action")||"",m.debug("No url or action specified, defaulting to form action",f)}m.set.loading(),t=e.extend(!0,{},p,{type:p.method||p.type,data:g,url:p.base+f,beforeSend:p.beforeXHR,success:function(){},failure:function(){},complete:function(){}}),m.debug("Querying URL",t.url),m.debug("Sending data",g,t.method),m.verbose("Using AJAX settings",t),m.is.loading()?m.timer=setTimeout(function(){m.request=m.create.request(),m.xhr=m.create.xhr(),p.onRequest.call(S,m.request,m.xhr)},p.throttle):(m.request=m.create.request(),m.xhr=m.create.xhr(),p.onRequest.call(S,m.request,m.xhr))},is:{disabled:function(){return D.filter(p.filter).length>0},form:function(){return D.is("form")},input:function(){return D.is("input")},loading:function(){return m.request&&"pending"==m.request.state()}},was:{cancelled:function(){return m.cancelled||!1},succesful:function(){return m.request&&"resolved"==m.request.state()},failure:function(){return m.request&&"rejected"==m.request.state()},complete:function(){return m.request&&("resolved"==m.request.state()||"rejected"==m.request.state())}},add:{urlData:function(t,r){var o,a;return t&&(o=t.match(p.regExp.required),a=t.match(p.regExp.optional),r=r||p.urlData,o&&(m.debug("Looking for required URL variables",o),e.each(o,function(o,a){var i=-1!==a.indexOf("$")?a.substr(2,a.length-3):a.substr(1,a.length-2),s=e.isPlainObject(r)&&r[i]!==n?r[i]:D.data(i)!==n?D.data(i):R.data(i)!==n?R.data(i):r[i];return s===n?(m.error(y.requiredParameter,i,t),t=!1,!1):(m.verbose("Found required variable",i,s),void(t=t.replace(a,s)))})),a&&(m.debug("Looking for optional URL variables",o),e.each(a,function(o,a){var i=-1!==a.indexOf("$")?a.substr(3,a.length-4):a.substr(2,a.length-3),s=e.isPlainObject(r)&&r[i]!==n?r[i]:D.data(i)!==n?D.data(i):R.data(i)!==n?R.data(i):r[i];s!==n?(m.verbose("Optional variable Found",i,s),t=t.replace(a,s)):(m.verbose("Optional variable not found",i),t=-1!==t.indexOf("/"+a)?t.replace("/"+a,""):t.replace(a,""))}))),t}},event:{trigger:function(e){m.query(),("submit"==e.type||"click"==e.type)&&e.preventDefault()},xhr:{always:function(){},done:function(e){var t=this,r=(new Date).getTime()-s,n=p.loadingDuration-r;n=n>0?n:0,setTimeout(function(){m.request.resolveWith(t,[e])},n)},fail:function(e,t,r){var n=this,o=(new Date).getTime()-s,a=p.loadingDuration-o;a=a>0?a:0,setTimeout(function(){"abort"!==t?m.request.rejectWith(n,[e,t,r]):m.reset()},a)}},request:{complete:function(e){m.remove.loading(),p.onComplete.call(S,e,D)},done:function(t){m.debug("API Response Received",t),"json"==p.dataType&&e.isFunction(p.successTest)?(m.debug("Checking JSON returned success",p.successTest,t),p.successTest(t)?p.onSuccess.call(S,t,D):(m.debug("JSON test specified by user and response failed",t),p.onFailure.call(S,t,D))):p.onSuccess.call(S,t,D)},error:function(r,o,a){var i,s=p.error[o]!==n?p.error[o]:a;if(r!==n)if(r.readyState!==n&&4==r.readyState){if(200!=r.status&&a!==n&&""!==a)m.error(y.statusMessage+a,t.url);else if("error"==o&&"json"==p.dataType)try{i=e.parseJSON(r.responseText),i&&i.error!==n&&(s=i.error)}catch(u){m.error(y.JSONParse)}m.remove.loading(),m.set.error(),p.errorDuration&&setTimeout(m.remove.error,p.errorDuration),m.debug("API Request error:",s),p.onError.call(S,s,D)}else p.onAbort.call(S,s,D),m.debug("Request Aborted (Most likely caused by page change or CORS Policy)",o,a)}}},create:{request:function(){return e.Deferred().always(m.event.request.complete).done(m.event.request.done).fail(m.event.request.error)},xhr:function(){return e.ajax(t).always(m.event.xhr.always).done(m.event.xhr.done).fail(m.event.xhr.fail)}},set:{error:function(){m.verbose("Adding error state to element",R),R.addClass(q.error)},loading:function(){m.verbose("Adding loading state to element",R),R.addClass(q.loading)}},remove:{error:function(){m.verbose("Removing error state from element",R),R.removeClass(q.error)},loading:function(){m.verbose("Removing loading state from element",R),R.removeClass(q.loading)}},get:{request:function(){return m.request||!1},xhr:function(){return m.xhr||!1},settings:function(){var e;return e=p.beforeSend.call(D,p),e&&(e.success!==n&&(m.debug("Legacy success callback detected",e),m.error(y.legacyParameters,e.success),e.onSuccess=e.success),e.failure!==n&&(m.debug("Legacy failure callback detected",e),m.error(y.legacyParameters,e.failure),e.onFailure=e.failure),e.complete!==n&&(m.debug("Legacy complete callback detected",e),m.error(y.legacyParameters,e.complete),e.onComplete=e.complete)),e===n&&m.error(y.noReturnedValue),e!==n?e:p},defaultData:function(){var t={};return e.isWindow(T)||(m.is.input()?t.value=D.val():m.is.form()&&(t.text=D.text())),t},event:function(){return e.isWindow(T)||"now"==p.on?(m.debug("API called without element, no events attached"),!1):"auto"==p.on?D.is("input")?T.oninput!==n?"input":T.onpropertychange!==n?"propertychange":"keyup":D.is("form")?"submit":"click":p.on},formData:function(){var e;return D.serializeObject!==n?e=P.serializeObject():(m.error(y.missingSerialize),e=P.serialize()),m.debug("Retrieved form data",e),e},templateURL:function(e){var t;return e=e||D.data(v.action)||p.action||!1,e&&(m.debug("Looking up url for action",e,p.api),p.api[e]!==n?(t=p.api[e],m.debug("Found template url",t)):m.is.form()||m.error(y.missingAction,p.action,p.api)),t}},abort:function(){var e=m.get.xhr();e&&"resolved"!==e.state()&&(m.debug("Cancelling API request"),e.abort(),m.request.rejectWith(p.apiSettings))},reset:function(){m.remove.error(),m.remove.loading()},setting:function(t,r){if(m.debug("Changing setting",t,r),e.isPlainObject(t))e.extend(!0,p,t);else{if(r===n)return p[t];p[t]=r}},internal:function(t,r){if(e.isPlainObject(t))e.extend(!0,m,t);else{if(r===n)return m[t];m[t]=r}},debug:function(){p.debug&&(p.performance?m.performance.log(arguments):(m.debug=Function.prototype.bind.call(console.info,console,p.name+":"),m.debug.apply(console,arguments)))},verbose:function(){p.verbose&&p.debug&&(p.performance?m.performance.log(arguments):(m.verbose=Function.prototype.bind.call(console.info,console,p.name+":"),m.verbose.apply(console,arguments)))},error:function(){m.error=Function.prototype.bind.call(console.error,console,p.name+":"),m.error.apply(console,arguments)},performance:{log:function(e){var t,r,n;p.performance&&(t=(new Date).getTime(),n=s||t,r=t-n,s=t,u.push({Name:e[0],Arguments:[].slice.call(e,1)||"","Execution Time":r})),clearTimeout(m.performance.timer),m.performance.timer=setTimeout(m.performance.display,100)},display:function(){var t=p.name+":",r=0;s=!1,clearTimeout(m.performance.timer),e.each(u,function(e,t){r+=t["Execution Time"]}),t+=" "+r+"ms",i&&(t+=" '"+i+"'"),(console.group!==n||console.table!==n)&&u.length>0&&(console.groupCollapsed(t),console.table?console.table(u):e.each(u,function(e,t){console.log(t.Name+": "+t["Execution Time"]+"ms")}),console.groupEnd()),u=[]}},invoke:function(t,r,a){var i,s,u,c=j;return r=r||d,a=T||a,"string"==typeof t&&c!==n&&(t=t.split(/[\. ]/),i=t.length-1,e.each(t,function(r,o){var a=r!=i?o+t[r+1].charAt(0).toUpperCase()+t[r+1].slice(1):t;if(e.isPlainObject(c[a])&&r!=i)c=c[a];else{if(c[a]!==n)return s=c[a],!1;if(!e.isPlainObject(c[o])||r==i)return c[o]!==n?(s=c[o],!1):(m.error(y.method,t),!1);c=c[o]}})),e.isFunction(s)?u=s.apply(a,r):s!==n&&(u=s),e.isArray(o)?o.push(u):o!==n?o=[o,u]:u!==n&&(o=u),s}},l?(j===n&&m.initialize(),m.invoke(c)):(j!==n&&j.invoke("destroy"),m.initialize())}),o!==n?o:this},e.api.settings={name:"API",namespace:"api",debug:!0,verbose:!1,performance:!0,on:"auto",filter:".disabled",stateContext:!1,loadingDuration:0,errorDuration:2e3,action:!1,url:!1,base:"",urlData:{},defaultData:!0,serializeForm:!1,throttle:0,method:"get",data:{},dataType:"json",beforeSend:function(e){return e},beforeXHR:function(e){},onRequest:function(e,t){},onSuccess:function(e,t){},onComplete:function(e,t){},onFailure:function(e,t){},onError:function(e,t){},onAbort:function(e,t){},successTest:!1,error:{beforeSend:"The before send function has aborted the request",error:"There was an error with your request",exitConditions:"API Request Aborted. Exit conditions met",JSONParse:"JSON could not be parsed during error handling",legacyParameters:"You are using legacy API success callback names",method:"The method you called is not defined",missingAction:"API action used but no url was defined",missingSerialize:"Required dependency jquery-serialize-object missing, using basic serialize",missingURL:"No URL specified for api event",noReturnedValue:"The beforeSend callback must return a settings object, beforeSend ignored.",parseError:"There was an error parsing your request",requiredParameter:"Missing a required URL parameter: ",statusMessage:"Server gave an error: ",timeout:"Your request timed out"},regExp:{required:/\{\$*[A-z0-9]+\}/g,optional:/\{\/\$*[A-z0-9]+\}/g},className:{loading:"loading",error:"error"},selector:{form:"form"},metadata:{action:"action"}},e.api.settings.api={}}(jQuery,window,document); | ||
!function(e,t,r,n){"use strict";e.api=e.fn.api=function(r){var o,s=e(e.isFunction(this)?t:this),a=s.selector||"",i=(new Date).getTime(),u=[],c=arguments[0],d="string"==typeof c,l=[].slice.call(arguments,1);return s.each(function(){var s,g,f,m,p,b,v=e.isPlainObject(r)?e.extend(!0,{},e.fn.api.settings,r):e.extend({},e.fn.api.settings),h=v.namespace,y=v.metadata,q=v.selector,R=v.error,x=v.className,k="."+h,A="module-"+h,S=e(this),T=S.closest(q.form),P=v.stateContext?e(v.stateContext):S,w=this,j=P[0],D=S.data(A);b={initialize:function(){d||b.bind.events(),b.instantiate()},instantiate:function(){b.verbose("Storing instance of module",b),D=b,S.data(A,D)},destroy:function(){b.verbose("Destroying previous module for",w),S.removeData(A).off(k)},bind:{events:function(){var e=b.get.event();e?(b.verbose("Attaching API events to element",e),S.on(e+k,b.event.trigger)):"now"==v.on&&(b.debug("Querying API now",e),b.query())}},read:{cachedResponse:function(e){var r;if(t.Storage===n)return void b.error(R.noStorage);if(r=sessionStorage.getItem(e),b.debug("Using cached response",e,r),r!==n){try{r=JSON.parse(r)}catch(o){}return r}return!1}},write:{cachedResponse:function(r,o){return o&&""===o?void b.debug("Response empty, not caching",o):t.Storage===n?void b.error(R.noStorage):(e.isPlainObject(o)&&(o=JSON.stringify(o)),sessionStorage.setItem(r,o),void b.verbose("Storing cached response for url",r,o))}},query:function(){if(b.is.disabled())return void b.debug("Element is disabled API request aborted");if(b.is.loading()){if(!v.interruptRequests)return void b.debug("Cancelling request, previous request is still pending");b.debug("Interrupting previous request"),b.abort()}return v.defaultData&&e.extend(!0,v.urlData,b.get.defaultData()),v.serializeForm&&(v.data=b.add.formData(v.data)),g=b.get.settings(),g===!1?(b.cancelled=!0,void b.error(R.beforeSend)):(b.cancelled=!1,f=b.get.templatedURL(),f||b.is.mocked()?(f=b.add.urlData(f),f||b.is.mocked()?(s=e.extend(!0,{},v,{type:v.method||v.type,data:m,url:v.base+f,beforeSend:v.beforeXHR,success:function(){},failure:function(){},complete:function(){}}),b.debug("Querying URL",s.url),b.verbose("Using AJAX settings",s),"local"===v.cache&&b.read.cachedResponse(f)?(b.debug("Response returned from local cache"),b.request=b.create.request(),void b.request.resolveWith(j,[b.read.cachedResponse(f)])):void(v.throttle?v.throttleFirstRequest||b.timer?(b.debug("Throttling request",v.throttle),clearTimeout(b.timer),b.timer=setTimeout(function(){b.timer&&delete b.timer,b.debug("Sending throttled request",m,s.method),b.send.request()},v.throttle)):(b.debug("Sending request",m,s.method),b.send.request(),b.timer=setTimeout(function(){},v.throttle)):(b.debug("Sending request",m,s.method),b.send.request()))):void 0):void b.error(R.missingURL))},is:{disabled:function(){return S.filter(q.disabled).length>0},form:function(){return S.is("form")},mocked:function(){return v.mockResponse||v.mockResponseAsync},input:function(){return S.is("input")},loading:function(){return b.request&&"pending"==b.request.state()},abortedRequest:function(e){return e&&e.readyState!==n&&0===e.readyState?(b.verbose("XHR request determined to be aborted"),!0):(b.verbose("XHR request was not aborted"),!1)},validResponse:function(t){return"json"===v.dataType&&e.isFunction(v.successTest)?(b.debug("Checking JSON returned success",v.successTest,t),v.successTest(t)?(b.debug("Response passed success test",t),!0):(b.debug("Response failed success test",t),!1)):(b.verbose("Response is not JSON, skipping validation",v.successTest,t),!0)}},was:{cancelled:function(){return b.cancelled||!1},succesful:function(){return b.request&&"resolved"==b.request.state()},failure:function(){return b.request&&"rejected"==b.request.state()},complete:function(){return b.request&&("resolved"==b.request.state()||"rejected"==b.request.state())}},add:{urlData:function(t,r){var o,s;return t&&(o=t.match(v.regExp.required),s=t.match(v.regExp.optional),r=r||v.urlData,o&&(b.debug("Looking for required URL variables",o),e.each(o,function(o,s){var a=-1!==s.indexOf("$")?s.substr(2,s.length-3):s.substr(1,s.length-2),i=e.isPlainObject(r)&&r[a]!==n?r[a]:S.data(a)!==n?S.data(a):P.data(a)!==n?P.data(a):r[a];return i===n?(b.error(R.requiredParameter,a,t),t=!1,!1):(b.verbose("Found required variable",a,i),void(t=t.replace(s,i)))})),s&&(b.debug("Looking for optional URL variables",o),e.each(s,function(o,s){var a=-1!==s.indexOf("$")?s.substr(3,s.length-4):s.substr(2,s.length-3),i=e.isPlainObject(r)&&r[a]!==n?r[a]:S.data(a)!==n?S.data(a):P.data(a)!==n?P.data(a):r[a];i!==n?(b.verbose("Optional variable Found",a,i),t=t.replace(s,i)):(b.verbose("Optional variable not found",a),t=-1!==t.indexOf("/"+s)?t.replace("/"+s,""):t.replace(s,""))}))),t},formData:function(t){var r,o=e.fn.serializeObject!==n,s=o?T.serializeObject():T.serialize();return t=t||v.data,r=e.isPlainObject(t),r?o?(b.debug("Extending existing data with form data",t,s),t=e.extend(!0,{},t,s)):(b.error(R.missingSerialize),b.debug("Cant extend data. Replacing data with form data",t,s),t=s):(b.debug("Adding form data",s),t=s),t}},send:{request:function(){b.set.loading(),b.request=b.create.request(),b.is.mocked()?b.mockedXHR=b.create.mockedXHR():b.xhr=b.create.xhr(),v.onRequest.call(j,b.request,b.xhr)}},event:{trigger:function(e){b.query(),("submit"==e.type||"click"==e.type)&&e.preventDefault()},xhr:{always:function(){},done:function(t,r,n){var o=this,s=(new Date).getTime()-p,a=v.loadingDuration-s,i=e.isFunction(v.onResponse)?v.onResponse.call(o,e.extend(!0,{},t)):!1;a=a>0?a:0,i&&(b.debug("Modified API response in onResponse callback",v.onResponse,i,t),t=i),a>0&&b.debug("Response completed early delaying state change by",a),setTimeout(function(){b.is.validResponse(t)?b.request.resolveWith(o,[t]):b.request.rejectWith(o,[n,"invalid"])},a)},fail:function(e,t,r){var n=this,o=(new Date).getTime()-p,s=v.loadingDuration-o;s=s>0?s:0,s>0&&b.debug("Response completed early delaying state change by",s),setTimeout(function(){b.is.abortedRequest(e)?b.request.rejectWith(n,[e,"aborted",r]):b.request.rejectWith(n,[e,"error",t,r])},s)}},request:{complete:function(e){b.remove.loading(),v.onComplete.call(j,e,S)},done:function(e){b.debug("Successful API Response",e),"local"===v.cache&&f&&(b.write.cachedResponse(f,e),b.debug("Saving server response locally",b.cache)),v.onSuccess.call(j,e,S)},fail:function(t,r,o){var a=e.isPlainObject(t)?t.responseText:!1,i=e.isPlainObject(a)&&a.error!==n?a.error:v.error[r]!==n?v.error[r]:o;"aborted"==r?(b.debug("XHR Aborted (Most likely caused by page navigation or CORS Policy)",r,o),v.onAbort.call(j,r,S)):"invalid"==r?b.debug("JSON did not pass success test. A server-side error has most likely occurred",a):"error"==r&&t!==n&&(b.debug("XHR produced a server error",r,o),200!=t.status&&o!==n&&""!==o&&b.error(R.statusMessage+o,s.url),v.onError.call(j,i,S)),v.errorDuration&&"aborted"!==r&&(b.debug("Adding error state"),b.set.error(),setTimeout(b.remove.error,v.errorDuration)),b.debug("API Request failed",i,t),v.onFailure.call(j,a,S)}}},create:{request:function(){return e.Deferred().always(b.event.request.complete).done(b.event.request.done).fail(b.event.request.fail)},mockedXHR:function(){var t,r,n,o=!1,s=!1,a=!1;return n=e.Deferred().always(b.event.xhr.complete).done(b.event.xhr.done).fail(b.event.xhr.fail),v.mockResponse?(e.isFunction(v.mockResponse)?(b.debug("Using mocked callback returning response",v.mockResponse),r=v.mockResponse.call(j,v)):(b.debug("Using specified response",v.mockResponse),r=v.mockResponse),n.resolveWith(j,[r,o,{responseText:r}])):e.isFunction(v.mockResponseAsync)&&(t=function(e){b.debug("Async callback returned response",e),e?n.resolveWith(j,[e,o,{responseText:e}]):n.rejectWith(j,[{responseText:e},s,a])},b.debug("Using async mocked response",v.mockResponseAsync),v.mockResponseAsync.call(j,v,t)),n},xhr:function(){var t;return t=e.ajax(s).always(b.event.xhr.always).done(b.event.xhr.done).fail(b.event.xhr.fail),b.verbose("Created server request",t),t}},set:{error:function(){b.verbose("Adding error state to element",P),P.addClass(x.error)},loading:function(){b.verbose("Adding loading state to element",P),P.addClass(x.loading),p=(new Date).getTime()}},remove:{error:function(){b.verbose("Removing error state from element",P),P.removeClass(x.error)},loading:function(){b.verbose("Removing loading state from element",P),P.removeClass(x.loading)}},get:{request:function(){return b.request||!1},xhr:function(){return b.xhr||!1},settings:function(){var e;return e=v.beforeSend.call(j,v),e&&(e.success!==n&&(b.debug("Legacy success callback detected",e),b.error(R.legacyParameters,e.success),e.onSuccess=e.success),e.failure!==n&&(b.debug("Legacy failure callback detected",e),b.error(R.legacyParameters,e.failure),e.onFailure=e.failure),e.complete!==n&&(b.debug("Legacy complete callback detected",e),b.error(R.legacyParameters,e.complete),e.onComplete=e.complete)),e===n&&b.error(R.noReturnedValue),e!==n?e:v},defaultData:function(){var t={};return e.isWindow(w)||(b.is.input()?t.value=S.val():b.is.form()&&(t.text=S.text())),t},event:function(){return e.isWindow(w)||"now"==v.on?(b.debug("API called without element, no events attached"),!1):"auto"==v.on?S.is("input")?w.oninput!==n?"input":w.onpropertychange!==n?"propertychange":"keyup":S.is("form")?"submit":"click":v.on},templatedURL:function(e){if(e=e||S.data(y.action)||v.action||!1,f=S.data(y.url)||v.url||!1)return b.debug("Using specified url",f),f;if(e){if(b.debug("Looking up url for action",e,v.api),v.api[e]===n&&!b.is.mocked())return void b.error(R.missingAction,v.action,v.api);f=v.api[e]}else b.is.form()&&(f=S.attr("action")||!1,b.debug("No url or action specified, defaulting to form action",f));return f}},abort:function(){var e=b.get.xhr();e&&"resolved"!==e.state()&&(b.debug("Cancelling API request"),e.abort())},reset:function(){b.remove.error(),b.remove.loading()},setting:function(t,r){if(b.debug("Changing setting",t,r),e.isPlainObject(t))e.extend(!0,v,t);else{if(r===n)return v[t];v[t]=r}},internal:function(t,r){if(e.isPlainObject(t))e.extend(!0,b,t);else{if(r===n)return b[t];b[t]=r}},debug:function(){v.debug&&(v.performance?b.performance.log(arguments):(b.debug=Function.prototype.bind.call(console.info,console,v.name+":"),b.debug.apply(console,arguments)))},verbose:function(){v.verbose&&v.debug&&(v.performance?b.performance.log(arguments):(b.verbose=Function.prototype.bind.call(console.info,console,v.name+":"),b.verbose.apply(console,arguments)))},error:function(){b.error=Function.prototype.bind.call(console.error,console,v.name+":"),b.error.apply(console,arguments)},performance:{log:function(e){var t,r,n;v.performance&&(t=(new Date).getTime(),n=i||t,r=t-n,i=t,u.push({Name:e[0],Arguments:[].slice.call(e,1)||"","Execution Time":r})),clearTimeout(b.performance.timer),b.performance.timer=setTimeout(b.performance.display,500)},display:function(){var t=v.name+":",r=0;i=!1,clearTimeout(b.performance.timer),e.each(u,function(e,t){r+=t["Execution Time"]}),t+=" "+r+"ms",a&&(t+=" '"+a+"'"),(console.group!==n||console.table!==n)&&u.length>0&&(console.groupCollapsed(t),console.table?console.table(u):e.each(u,function(e,t){console.log(t.Name+": "+t["Execution Time"]+"ms")}),console.groupEnd()),u=[]}},invoke:function(t,r,s){var a,i,u,c=D;return r=r||l,s=w||s,"string"==typeof t&&c!==n&&(t=t.split(/[\. ]/),a=t.length-1,e.each(t,function(r,o){var s=r!=a?o+t[r+1].charAt(0).toUpperCase()+t[r+1].slice(1):t;if(e.isPlainObject(c[s])&&r!=a)c=c[s];else{if(c[s]!==n)return i=c[s],!1;if(!e.isPlainObject(c[o])||r==a)return c[o]!==n?(i=c[o],!1):(b.error(R.method,t),!1);c=c[o]}})),e.isFunction(i)?u=i.apply(s,r):i!==n&&(u=i),e.isArray(o)?o.push(u):o!==n?o=[o,u]:u!==n&&(o=u),i}},d?(D===n&&b.initialize(),b.invoke(c)):(D!==n&&D.invoke("destroy"),b.initialize())}),o!==n?o:this},e.api.settings={name:"API",namespace:"api",debug:!0,verbose:!1,performance:!0,api:{},cache:!0,interruptRequests:!0,on:"auto",stateContext:!1,loadingDuration:0,errorDuration:2e3,action:!1,url:!1,base:"",urlData:{},defaultData:!0,serializeForm:!1,throttle:0,throttleFirstRequest:!0,method:"get",data:{},dataType:"json",mockResponse:!1,mockResponseAsync:!1,beforeSend:function(e){return e},beforeXHR:function(e){},onRequest:function(e,t){},onResponse:!1,onSuccess:function(e,t){},onComplete:function(e,t){},onFailure:function(e,t){},onError:function(e,t){},onAbort:function(e,t){},successTest:!1,error:{beforeSend:"The before send function has aborted the request",error:"There was an error with your request",exitConditions:"API Request Aborted. Exit conditions met",JSONParse:"JSON could not be parsed during error handling",legacyParameters:"You are using legacy API success callback names",method:"The method you called is not defined",missingAction:"API action used but no url was defined",missingSerialize:"jquery-serialize-object is required to add form data to an existing data object",missingURL:"No URL specified for api event",noReturnedValue:"The beforeSend callback must return a settings object, beforeSend ignored.",noStorage:"Caching respopnses locally requires session storage",parseError:"There was an error parsing your request",requiredParameter:"Missing a required URL parameter: ",statusMessage:"Server gave an error: ",timeout:"Your request timed out"},regExp:{required:/\{\$*[A-z0-9]+\}/g,optional:/\{\/\$*[A-z0-9]+\}/g},className:{loading:"loading",error:"error"},selector:{disabled:".disabled",form:"form"},metadata:{action:"action",url:"url"}}}(jQuery,window,document); |
@@ -18,3 +18,3 @@ { | ||
"license": "MIT", | ||
"version": "1.12.3" | ||
"version": "2.0.2" | ||
} |
584
index.js
/*! | ||
* # Semantic UI 1.12.3 - API | ||
* # Semantic UI 2.0.2 - API | ||
* http://github.com/semantic-org/semantic-ui/ | ||
* | ||
* | ||
* Copyright 2014 Contributors | ||
* Copyright 2015 Contributors | ||
* Released under the MIT license | ||
@@ -67,6 +67,7 @@ * http://opensource.org/licenses/MIT | ||
data, | ||
requestStartTime, | ||
// standard module | ||
element = this, | ||
context = $context.get(), | ||
context = $context[0], | ||
instance = $module.data(moduleNamespace), | ||
@@ -79,17 +80,4 @@ module | ||
initialize: function() { | ||
var | ||
triggerEvent = module.get.event() | ||
; | ||
// bind events | ||
if(!methodInvoked) { | ||
if( triggerEvent ) { | ||
module.debug('Attaching API events to element', triggerEvent); | ||
$module | ||
.on(triggerEvent + eventNamespace, module.event.trigger) | ||
; | ||
} | ||
else if(settings.on == 'now') { | ||
module.debug('Querying API now', triggerEvent); | ||
module.query(); | ||
} | ||
module.bind.events(); | ||
} | ||
@@ -115,2 +103,61 @@ module.instantiate(); | ||
bind: { | ||
events: function() { | ||
var | ||
triggerEvent = module.get.event() | ||
; | ||
if( triggerEvent ) { | ||
module.verbose('Attaching API events to element', triggerEvent); | ||
$module | ||
.on(triggerEvent + eventNamespace, module.event.trigger) | ||
; | ||
} | ||
else if(settings.on == 'now') { | ||
module.debug('Querying API now', triggerEvent); | ||
module.query(); | ||
} | ||
} | ||
}, | ||
read: { | ||
cachedResponse: function(url) { | ||
var | ||
response | ||
; | ||
if(window.Storage === undefined) { | ||
module.error(error.noStorage); | ||
return; | ||
} | ||
response = sessionStorage.getItem(url); | ||
module.debug('Using cached response', url, response); | ||
if(response !== undefined) { | ||
try { | ||
response = JSON.parse(response); | ||
} | ||
catch(e) { | ||
// didnt store object | ||
} | ||
return response; | ||
} | ||
return false; | ||
} | ||
}, | ||
write: { | ||
cachedResponse: function(url, response) { | ||
if(response && response === '') { | ||
module.debug('Response empty, not caching', response); | ||
return; | ||
} | ||
if(window.Storage === undefined) { | ||
module.error(error.noStorage); | ||
return; | ||
} | ||
if( $.isPlainObject(response) ) { | ||
response = JSON.stringify(response); | ||
} | ||
sessionStorage.setItem(url, response); | ||
module.verbose('Storing cached response for url', url, response); | ||
} | ||
}, | ||
query: function() { | ||
@@ -122,6 +169,12 @@ | ||
} | ||
// determine if an api event already occurred | ||
if(module.is.loading() && settings.throttle === 0 ) { | ||
module.debug('Cancelling request, previous request is still pending'); | ||
return; | ||
if(module.is.loading()) { | ||
if(settings.interruptRequests) { | ||
module.debug('Interrupting previous request'); | ||
module.abort(); | ||
} | ||
else { | ||
module.debug('Cancelling request, previous request is still pending'); | ||
return; | ||
} | ||
} | ||
@@ -135,13 +188,8 @@ | ||
// Add form content | ||
if(settings.serializeForm !== false || $context.is('form')) { | ||
if(settings.serializeForm == 'json') { | ||
$.extend(true, settings.data, module.get.formData()); | ||
} | ||
else { | ||
settings.data = module.get.formData(); | ||
} | ||
if(settings.serializeForm) { | ||
settings.data = module.add.formData(settings.data); | ||
} | ||
// call beforesend and get any settings changes | ||
requestSettings = module.get.settings(); | ||
requestSettings = module.get.settings(); | ||
@@ -158,27 +206,18 @@ // check if before send cancelled request | ||
if(settings.url) { | ||
// override with url if specified | ||
module.debug('Using specified url', url); | ||
url = module.add.urlData( settings.url ); | ||
// get url | ||
url = module.get.templatedURL(); | ||
if(!url && !module.is.mocked()) { | ||
module.error(error.missingURL); | ||
return; | ||
} | ||
else { | ||
// otherwise find url from api endpoints | ||
url = module.add.urlData( module.get.templateURL() ); | ||
module.debug('Added URL Data to url', url); | ||
} | ||
// exit conditions reached, missing url parameters | ||
if( !url ) { | ||
if( module.is.form() ) { | ||
url = $module.attr('action') || ''; | ||
module.debug('No url or action specified, defaulting to form action', url); | ||
} | ||
else { | ||
module.error(error.missingURL, settings.action); | ||
return; | ||
} | ||
// replace variables | ||
url = module.add.urlData( url ); | ||
// missing url parameters | ||
if( !url && !module.is.mocked()) { | ||
return; | ||
} | ||
// add loading state | ||
module.set.loading(); | ||
@@ -197,18 +236,32 @@ // look for require("jquery") ajax parameters in settings | ||
module.debug('Querying URL', ajaxSettings.url); | ||
module.debug('Sending data', data, ajaxSettings.method); | ||
module.verbose('Using AJAX settings', ajaxSettings); | ||
if( module.is.loading() ) { | ||
// throttle additional requests | ||
module.timer = setTimeout(function() { | ||
module.request = module.create.request(); | ||
module.xhr = module.create.xhr(); | ||
settings.onRequest.call(context, module.request, module.xhr); | ||
}, settings.throttle); | ||
if(settings.cache === 'local' && module.read.cachedResponse(url)) { | ||
module.debug('Response returned from local cache'); | ||
module.request = module.create.request(); | ||
module.request.resolveWith(context, [ module.read.cachedResponse(url) ]); | ||
return; | ||
} | ||
if( !settings.throttle ) { | ||
module.debug('Sending request', data, ajaxSettings.method); | ||
module.send.request(); | ||
} | ||
else { | ||
// immediately on first request | ||
module.request = module.create.request(); | ||
module.xhr = module.create.xhr(); | ||
settings.onRequest.call(context, module.request, module.xhr); | ||
if(!settings.throttleFirstRequest && !module.timer) { | ||
module.debug('Sending request', data, ajaxSettings.method); | ||
module.send.request(); | ||
module.timer = setTimeout(function(){}, settings.throttle); | ||
} | ||
else { | ||
module.debug('Throttling request', settings.throttle); | ||
clearTimeout(module.timer); | ||
module.timer = setTimeout(function() { | ||
if(module.timer) { | ||
delete module.timer; | ||
} | ||
module.debug('Sending throttled request', data, ajaxSettings.method); | ||
module.send.request(); | ||
}, settings.throttle); | ||
} | ||
} | ||
@@ -218,6 +271,5 @@ | ||
is: { | ||
disabled: function() { | ||
return ($module.filter(settings.filter).length > 0); | ||
return ($module.filter(selector.disabled).length > 0); | ||
}, | ||
@@ -227,2 +279,5 @@ form: function() { | ||
}, | ||
mocked: function() { | ||
return (settings.mockResponse || settings.mockResponseAsync); | ||
}, | ||
input: function() { | ||
@@ -233,2 +288,27 @@ return $module.is('input'); | ||
return (module.request && module.request.state() == 'pending'); | ||
}, | ||
abortedRequest: function(xhr) { | ||
if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) { | ||
module.verbose('XHR request determined to be aborted'); | ||
return true; | ||
} | ||
else { | ||
module.verbose('XHR request was not aborted'); | ||
return false; | ||
} | ||
}, | ||
validResponse: function(response) { | ||
if( settings.dataType !== 'json' || !$.isFunction(settings.successTest) ) { | ||
module.verbose('Response is not JSON, skipping validation', settings.successTest, response); | ||
return true; | ||
} | ||
module.debug('Checking JSON returned success', settings.successTest, response); | ||
if( settings.successTest(response) ) { | ||
module.debug('Response passed success test', response); | ||
return true; | ||
} | ||
else { | ||
module.debug('Response failed success test', response); | ||
return false; | ||
} | ||
} | ||
@@ -325,5 +405,47 @@ }, | ||
return url; | ||
}, | ||
formData: function(data) { | ||
var | ||
canSerialize = ($.fn.serializeObject !== undefined), | ||
formData = (canSerialize) | ||
? $form.serializeObject() | ||
: $form.serialize(), | ||
hasOtherData | ||
; | ||
data = data || settings.data; | ||
hasOtherData = $.isPlainObject(data); | ||
if(hasOtherData) { | ||
if(canSerialize) { | ||
module.debug('Extending existing data with form data', data, formData); | ||
data = $.extend(true, {}, data, formData); | ||
} | ||
else { | ||
module.error(error.missingSerialize); | ||
module.debug('Cant extend data. Replacing data with form data', data, formData); | ||
data = formData; | ||
} | ||
} | ||
else { | ||
module.debug('Adding form data', formData); | ||
data = formData; | ||
} | ||
return data; | ||
} | ||
}, | ||
send: { | ||
request: function() { | ||
module.set.loading(); | ||
module.request = module.create.request(); | ||
if( module.is.mocked() ) { | ||
module.mockedXHR = module.create.mockedXHR(); | ||
} | ||
else { | ||
module.xhr = module.create.xhr(); | ||
} | ||
settings.onRequest.call(context, module.request, module.xhr); | ||
} | ||
}, | ||
event: { | ||
@@ -340,7 +462,10 @@ trigger: function(event) { | ||
}, | ||
done: function(response) { | ||
done: function(response, textStatus, xhr) { | ||
var | ||
context = this, | ||
elapsedTime = (new Date().getTime() - time), | ||
timeLeft = (settings.loadingDuration - elapsedTime) | ||
elapsedTime = (new Date().getTime() - requestStartTime), | ||
timeLeft = (settings.loadingDuration - elapsedTime), | ||
translatedResponse = ( $.isFunction(settings.onResponse) ) | ||
? settings.onResponse.call(context, $.extend(true, {}, response)) | ||
: false | ||
; | ||
@@ -351,4 +476,16 @@ timeLeft = (timeLeft > 0) | ||
; | ||
if(translatedResponse) { | ||
module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response); | ||
response = translatedResponse; | ||
} | ||
if(timeLeft > 0) { | ||
module.debug('Response completed early delaying state change by', timeLeft); | ||
} | ||
setTimeout(function() { | ||
module.request.resolveWith(context, [response]); | ||
if( module.is.validResponse(response) ) { | ||
module.request.resolveWith(context, [response]); | ||
} | ||
else { | ||
module.request.rejectWith(context, [xhr, 'invalid']); | ||
} | ||
}, timeLeft); | ||
@@ -359,3 +496,3 @@ }, | ||
context = this, | ||
elapsedTime = (new Date().getTime() - time), | ||
elapsedTime = (new Date().getTime() - requestStartTime), | ||
timeLeft = (settings.loadingDuration - elapsedTime) | ||
@@ -367,9 +504,11 @@ ; | ||
; | ||
// page triggers abort on navigation, dont show error | ||
if(timeLeft > 0) { | ||
module.debug('Response completed early delaying state change by', timeLeft); | ||
} | ||
setTimeout(function() { | ||
if(status !== 'abort') { | ||
module.request.rejectWith(context, [xhr, status, httpMessage]); | ||
if( module.is.abortedRequest(xhr) ) { | ||
module.request.rejectWith(context, [xhr, 'aborted', httpMessage]); | ||
} | ||
else { | ||
module.reset(); | ||
module.request.rejectWith(context, [xhr, 'error', status, httpMessage]); | ||
} | ||
@@ -385,65 +524,47 @@ }, timeLeft); | ||
done: function(response) { | ||
module.debug('API Response Received', response); | ||
if(settings.dataType == 'json') { | ||
if( $.isFunction(settings.successTest) ) { | ||
module.debug('Checking JSON returned success', settings.successTest, response); | ||
if( settings.successTest(response) ) { | ||
settings.onSuccess.call(context, response, $module); | ||
} | ||
else { | ||
module.debug('JSON test specified by user and response failed', response); | ||
settings.onFailure.call(context, response, $module); | ||
} | ||
} | ||
else { | ||
settings.onSuccess.call(context, response, $module); | ||
} | ||
module.debug('Successful API Response', response); | ||
if(settings.cache === 'local' && url) { | ||
module.write.cachedResponse(url, response); | ||
module.debug('Saving server response locally', module.cache); | ||
} | ||
else { | ||
settings.onSuccess.call(context, response, $module); | ||
} | ||
settings.onSuccess.call(context, response, $module); | ||
}, | ||
error: function(xhr, status, httpMessage) { | ||
fail: function(xhr, status, httpMessage) { | ||
var | ||
errorMessage = (settings.error[status] !== undefined) | ||
? settings.error[status] | ||
: httpMessage, | ||
response | ||
// pull response from xhr if available | ||
response = $.isPlainObject(xhr) | ||
? (xhr.responseText) | ||
: false, | ||
errorMessage = ($.isPlainObject(response) && response.error !== undefined) | ||
? response.error // use json error message | ||
: (settings.error[status] !== undefined) // use server error message | ||
? settings.error[status] | ||
: httpMessage | ||
; | ||
// let em know unless request aborted | ||
if(xhr !== undefined) { | ||
// readyState 4 = done, anything less is not really sent | ||
if(xhr.readyState !== undefined && xhr.readyState == 4) { | ||
if(status == 'aborted') { | ||
module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage); | ||
settings.onAbort.call(context, status, $module); | ||
} | ||
else if(status == 'invalid') { | ||
module.debug('JSON did not pass success test. A server-side error has most likely occurred', response); | ||
} | ||
else if(status == 'error') { | ||
// if http status code returned and json returned error, look for it | ||
if(xhr !== undefined) { | ||
module.debug('XHR produced a server error', status, httpMessage); | ||
// make sure we have an error to display to console | ||
if( xhr.status != 200 && httpMessage !== undefined && httpMessage !== '') { | ||
module.error(error.statusMessage + httpMessage, ajaxSettings.url); | ||
} | ||
else { | ||
if(status == 'error' && settings.dataType == 'json') { | ||
try { | ||
response = $.parseJSON(xhr.responseText); | ||
if(response && response.error !== undefined) { | ||
errorMessage = response.error; | ||
} | ||
} | ||
catch(e) { | ||
module.error(error.JSONParse); | ||
} | ||
} | ||
} | ||
module.remove.loading(); | ||
module.set.error(); | ||
// show error state only for duration specified in settings | ||
if(settings.errorDuration) { | ||
setTimeout(module.remove.error, settings.errorDuration); | ||
} | ||
module.debug('API Request error:', errorMessage); | ||
settings.onError.call(context, errorMessage, $module); | ||
} | ||
else { | ||
settings.onAbort.call(context, errorMessage, $module); | ||
module.debug('Request Aborted (Most likely caused by page change or CORS Policy)', status, httpMessage); | ||
} | ||
} | ||
if(settings.errorDuration && status !== 'aborted') { | ||
module.debug('Adding error state'); | ||
module.set.error(); | ||
setTimeout(module.remove.error, settings.errorDuration); | ||
} | ||
module.debug('API Request failed', errorMessage, xhr); | ||
settings.onFailure.call(context, response, $module); | ||
} | ||
@@ -454,11 +575,64 @@ } | ||
create: { | ||
request: function() { | ||
// api request promise | ||
return $.Deferred() | ||
.always(module.event.request.complete) | ||
.done(module.event.request.done) | ||
.fail(module.event.request.error) | ||
.fail(module.event.request.fail) | ||
; | ||
}, | ||
mockedXHR: function () { | ||
var | ||
// xhr does not simulate these properties of xhr but must return them | ||
textStatus = false, | ||
status = false, | ||
httpMessage = false, | ||
asyncCallback, | ||
response, | ||
mockedXHR | ||
; | ||
mockedXHR = $.Deferred() | ||
.always(module.event.xhr.complete) | ||
.done(module.event.xhr.done) | ||
.fail(module.event.xhr.fail) | ||
; | ||
if(settings.mockResponse) { | ||
if( $.isFunction(settings.mockResponse) ) { | ||
module.debug('Using mocked callback returning response', settings.mockResponse); | ||
response = settings.mockResponse.call(context, settings); | ||
} | ||
else { | ||
module.debug('Using specified response', settings.mockResponse); | ||
response = settings.mockResponse; | ||
} | ||
// simulating response | ||
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); | ||
} | ||
else if( $.isFunction(settings.mockResponseAsync) ) { | ||
asyncCallback = function(response) { | ||
module.debug('Async callback returned response', response); | ||
if(response) { | ||
mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); | ||
} | ||
else { | ||
mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]); | ||
} | ||
}; | ||
module.debug('Using async mocked response', settings.mockResponseAsync); | ||
settings.mockResponseAsync.call(context, settings, asyncCallback); | ||
} | ||
return mockedXHR; | ||
}, | ||
xhr: function() { | ||
return $.ajax(ajaxSettings) | ||
var | ||
xhr | ||
; | ||
// ajax request promise | ||
xhr = $.ajax(ajaxSettings) | ||
.always(module.event.xhr.always) | ||
@@ -468,2 +642,4 @@ .done(module.event.xhr.done) | ||
; | ||
module.verbose('Created server request', xhr); | ||
return xhr; | ||
} | ||
@@ -480,2 +656,3 @@ }, | ||
$context.addClass(className.loading); | ||
requestStartTime = new Date().getTime(); | ||
} | ||
@@ -506,3 +683,3 @@ }, | ||
; | ||
runSettings = settings.beforeSend.call($module, settings); | ||
runSettings = settings.beforeSend.call(context, settings); | ||
if(runSettings) { | ||
@@ -575,31 +752,21 @@ if(runSettings.success !== undefined) { | ||
}, | ||
formData: function() { | ||
var | ||
formData | ||
; | ||
if($module.serializeObject !== undefined) { | ||
formData = $form.serializeObject(); | ||
templatedURL: function(action) { | ||
action = action || $module.data(metadata.action) || settings.action || false; | ||
url = $module.data(metadata.url) || settings.url || false; | ||
if(url) { | ||
module.debug('Using specified url', url); | ||
return url; | ||
} | ||
else { | ||
module.error(error.missingSerialize); | ||
formData = $form.serialize(); | ||
} | ||
module.debug('Retrieved form data', formData); | ||
return formData; | ||
}, | ||
templateURL: function(action) { | ||
var | ||
url | ||
; | ||
action = action || $module.data(metadata.action) || settings.action || false; | ||
if(action) { | ||
module.debug('Looking up url for action', action, settings.api); | ||
if(settings.api[action] !== undefined) { | ||
url = settings.api[action]; | ||
module.debug('Found template url', url); | ||
} | ||
else if( !module.is.form() ) { | ||
if(settings.api[action] === undefined && !module.is.mocked()) { | ||
module.error(error.missingAction, settings.action, settings.api); | ||
return; | ||
} | ||
url = settings.api[action]; | ||
} | ||
else if( module.is.form() ) { | ||
url = $module.attr('action') || false; | ||
module.debug('No url or action specified, defaulting to form action', url); | ||
} | ||
return url; | ||
@@ -616,3 +783,2 @@ } | ||
xhr.abort(); | ||
module.request.rejectWith(settings.apiSettings); | ||
} | ||
@@ -696,3 +862,3 @@ }, | ||
clearTimeout(module.performance.timer); | ||
module.performance.timer = setTimeout(module.performance.display, 100); | ||
module.performance.timer = setTimeout(module.performance.display, 500); | ||
}, | ||
@@ -807,45 +973,84 @@ display: function() { | ||
name : 'API', | ||
namespace : 'api', | ||
name : 'API', | ||
namespace : 'api', | ||
debug : true, | ||
verbose : false, | ||
performance : true, | ||
debug : true, | ||
verbose : false, | ||
performance : true, | ||
// object containing all templates endpoints | ||
api : {}, | ||
// whether to cache responses | ||
cache : true, | ||
// whether new requests should abort previous requests | ||
interruptRequests : true, | ||
// event binding | ||
on : 'auto', | ||
filter : '.disabled', | ||
stateContext : false, | ||
on : 'auto', | ||
// state | ||
loadingDuration : 0, | ||
errorDuration : 2000, | ||
// context for applying state classes | ||
stateContext : false, | ||
// templating | ||
action : false, | ||
url : false, | ||
base : '', | ||
// duration for loading state | ||
loadingDuration : 0, | ||
// data | ||
urlData : {}, | ||
// duration for error state | ||
errorDuration : 2000, | ||
// ui | ||
defaultData : true, | ||
serializeForm : false, | ||
throttle : 0, | ||
// API action to use | ||
action : false, | ||
// jQ ajax | ||
method : 'get', | ||
data : {}, | ||
dataType : 'json', | ||
// templated URL to use | ||
url : false, | ||
// callbacks | ||
// base URL to apply to all endpoints | ||
base : '', | ||
// data that will | ||
urlData : {}, | ||
// whether to add default data to url data | ||
defaultData : true, | ||
// whether to serialize closest form | ||
serializeForm : false, | ||
// how long to wait before request should occur | ||
throttle : 0, | ||
// whether to throttle first request or only repeated | ||
throttleFirstRequest : true, | ||
// standard ajax settings | ||
method : 'get', | ||
data : {}, | ||
dataType : 'json', | ||
// mock response | ||
mockResponse : false, | ||
mockResponseAsync : false, | ||
// callbacks before request | ||
beforeSend : function(settings) { return settings; }, | ||
beforeXHR : function(xhr) {}, | ||
onRequest : function(promise, xhr) {}, | ||
onRequest : function(promise, xhr) {}, | ||
// after request | ||
onResponse : false, // function(response) { }, | ||
// response was successful, if JSON passed validation | ||
onSuccess : function(response, $module) {}, | ||
// request finished without aborting | ||
onComplete : function(response, $module) {}, | ||
onFailure : function(errorMessage, $module) {}, | ||
// failed JSON success test | ||
onFailure : function(response, $module) {}, | ||
// server error | ||
onError : function(errorMessage, $module) {}, | ||
// request aborted | ||
onAbort : function(errorMessage, $module) {}, | ||
@@ -864,5 +1069,6 @@ | ||
missingAction : 'API action used but no url was defined', | ||
missingSerialize : 'Required dependency jquery-serialize-object missing, using basic serialize', | ||
missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object', | ||
missingURL : 'No URL specified for api event', | ||
noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.', | ||
noStorage : 'Caching respopnses locally requires session storage', | ||
parseError : 'There was an error parsing your request', | ||
@@ -875,4 +1081,4 @@ requiredParameter : 'Missing a required URL parameter: ', | ||
regExp : { | ||
required: /\{\$*[A-z0-9]+\}/g, | ||
optional: /\{\/\$*[A-z0-9]+\}/g, | ||
required : /\{\$*[A-z0-9]+\}/g, | ||
optional : /\{\/\$*[A-z0-9]+\}/g, | ||
}, | ||
@@ -886,7 +1092,9 @@ | ||
selector: { | ||
form: 'form' | ||
disabled : '.disabled', | ||
form : 'form' | ||
}, | ||
metadata: { | ||
action : 'action' | ||
action : 'action', | ||
url : 'url' | ||
} | ||
@@ -896,5 +1104,3 @@ }; | ||
$.api.settings.api = {}; | ||
})( require("jquery"), window , document ); | ||
})( require("jquery"), window , document ); |
@@ -5,3 +5,3 @@ | ||
summary : 'Semantic UI - Api: Single component release', | ||
version : '1.12.3', | ||
version : '2.0.2', | ||
git : 'git://github.com/Semantic-Org/UI-Api.git', | ||
@@ -8,0 +8,0 @@ }); |
{ | ||
"name": "semantic-ui-api", | ||
"version": "1.12.3", | ||
"version": "2.0.2", | ||
"title": "Semantic UI - Api", | ||
@@ -5,0 +5,0 @@ "description": "Single component release of api", |
@@ -0,1 +1,22 @@ | ||
### Version 2.0.1 - July 6, 2015 | ||
- **Tab** - Tab now correctly obeys `cache` setting. Removed use of API's local caching by default. [#2493](https://github.com/Semantic-Org/Semantic-UI/issues/2493) | ||
### Version 2.0.0 - June 30, 2015 | ||
- **API** - API `onFailure` will now be called **in all failure conditions**, when a request is errored (504, 404 etc), aborted (page change or CORS), or JSON does not pass `successTest` function. `onError` and `onAbort` will also fire for each specific failure condition. | ||
- **Multiselect** - New `multiple` dropdown types have been added. Many new dropdown improvements have been added including tagging/tokenizing features and loading data through API requests. | ||
- **API** - API can now be used with mocked responses, and custom AJAX requests. `mockResponse` has been added to resolve request with a prespecified JSON object, or a synchronous function callback. | ||
- **API** `mockResponseAsync` has been added for custom asynchronous requests. This allows you to specify a custom async callback to resolve an API request, helping with integration with libraries like Ember or Angular that may wrap AJAX requests. | ||
- **API** - API callbacks now have an `onResponse` callback that can adjust a servers response before it is parsed by other callbacks for success or failure conditions. **Thanks @mnquintana** | ||
- **API** - API now provides a local caching setting to avoid server roundtrips for identical urls by using `cache: 'local'`. This is not enabled by default. Local caching is useful for results that should return the same values across a single session, for example when querying an autocomplete. | ||
- **Dropdown** - Added remote API integration with dropdown, to allow `search selection` to query against a remote dataset. | ||
- **API** - API now has new settings `throttleFirstRequest` and `interruptRequests`. Interrupt requests will abort a previous request on an element when making a new request. `throttleFirstRequest`, sets whether the first request or only subsequent requests should be throttled when a `throttle` duration is specified. | ||
- **Accordion** - Fixed bug where `exclusive: true` could sometimes cause other accordion element animations to get stuck when animating rapidly | ||
- **API** - API longer uses `readyState = 0` as sole check for request abort, this may accidentally trigger with `JSONP` or `CORS` requests. | ||
- **API** - Fixed `this` context of `beforeSend` to use `stateContext` not `element` | ||
- **API** - Fixed `loadingDuration` not correctly delaying requests when invoking with `.api('query')` | ||
- **Search** - Search will no longer incorrectly produce an error when API settings are passed through metadata | ||
- **Search** - Search API calls now use the same level debug settings as search | ||
### Version 1.11.0 - March 3, 2015 | ||
@@ -2,0 +23,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
93946
2031