| @@ 19706-20862 (lines=1157) @@ | ||
| 19703 | * |
|
| 19704 | */ |
|
| 19705 | ||
| 19706 | ;(function ($, window, document, undefined) { |
|
| 19707 | ||
| 19708 | "use strict"; |
|
| 19709 | ||
| 19710 | var |
|
| 19711 | window = (typeof window != 'undefined' && window.Math == Math) |
|
| 19712 | ? window |
|
| 19713 | : (typeof self != 'undefined' && self.Math == Math) |
|
| 19714 | ? self |
|
| 19715 | : Function('return this')() |
|
| 19716 | ; |
|
| 19717 | ||
| 19718 | $.api = $.fn.api = function(parameters) { |
|
| 19719 | ||
| 19720 | var |
|
| 19721 | // use window context if none specified |
|
| 19722 | $allModules = $.isFunction(this) |
|
| 19723 | ? $(window) |
|
| 19724 | : $(this), |
|
| 19725 | moduleSelector = $allModules.selector || '', |
|
| 19726 | time = new Date().getTime(), |
|
| 19727 | performance = [], |
|
| 19728 | ||
| 19729 | query = arguments[0], |
|
| 19730 | methodInvoked = (typeof query == 'string'), |
|
| 19731 | queryArguments = [].slice.call(arguments, 1), |
|
| 19732 | ||
| 19733 | returnedValue |
|
| 19734 | ; |
|
| 19735 | ||
| 19736 | $allModules |
|
| 19737 | .each(function() { |
|
| 19738 | var |
|
| 19739 | settings = ( $.isPlainObject(parameters) ) |
|
| 19740 | ? $.extend(true, {}, $.fn.api.settings, parameters) |
|
| 19741 | : $.extend({}, $.fn.api.settings), |
|
| 19742 | ||
| 19743 | // internal aliases |
|
| 19744 | namespace = settings.namespace, |
|
| 19745 | metadata = settings.metadata, |
|
| 19746 | selector = settings.selector, |
|
| 19747 | error = settings.error, |
|
| 19748 | className = settings.className, |
|
| 19749 | ||
| 19750 | // define namespaces for modules |
|
| 19751 | eventNamespace = '.' + namespace, |
|
| 19752 | moduleNamespace = 'module-' + namespace, |
|
| 19753 | ||
| 19754 | // element that creates request |
|
| 19755 | $module = $(this), |
|
| 19756 | $form = $module.closest(selector.form), |
|
| 19757 | ||
| 19758 | // context used for state |
|
| 19759 | $context = (settings.stateContext) |
|
| 19760 | ? $(settings.stateContext) |
|
| 19761 | : $module, |
|
| 19762 | ||
| 19763 | // request details |
|
| 19764 | ajaxSettings, |
|
| 19765 | requestSettings, |
|
| 19766 | url, |
|
| 19767 | data, |
|
| 19768 | requestStartTime, |
|
| 19769 | ||
| 19770 | // standard module |
|
| 19771 | element = this, |
|
| 19772 | context = $context[0], |
|
| 19773 | instance = $module.data(moduleNamespace), |
|
| 19774 | module |
|
| 19775 | ; |
|
| 19776 | ||
| 19777 | module = { |
|
| 19778 | ||
| 19779 | initialize: function() { |
|
| 19780 | if(!methodInvoked) { |
|
| 19781 | module.bind.events(); |
|
| 19782 | } |
|
| 19783 | module.instantiate(); |
|
| 19784 | }, |
|
| 19785 | ||
| 19786 | instantiate: function() { |
|
| 19787 | module.verbose('Storing instance of module', module); |
|
| 19788 | instance = module; |
|
| 19789 | $module |
|
| 19790 | .data(moduleNamespace, instance) |
|
| 19791 | ; |
|
| 19792 | }, |
|
| 19793 | ||
| 19794 | destroy: function() { |
|
| 19795 | module.verbose('Destroying previous module for', element); |
|
| 19796 | $module |
|
| 19797 | .removeData(moduleNamespace) |
|
| 19798 | .off(eventNamespace) |
|
| 19799 | ; |
|
| 19800 | }, |
|
| 19801 | ||
| 19802 | bind: { |
|
| 19803 | events: function() { |
|
| 19804 | var |
|
| 19805 | triggerEvent = module.get.event() |
|
| 19806 | ; |
|
| 19807 | if( triggerEvent ) { |
|
| 19808 | module.verbose('Attaching API events to element', triggerEvent); |
|
| 19809 | $module |
|
| 19810 | .on(triggerEvent + eventNamespace, module.event.trigger) |
|
| 19811 | ; |
|
| 19812 | } |
|
| 19813 | else if(settings.on == 'now') { |
|
| 19814 | module.debug('Querying API endpoint immediately'); |
|
| 19815 | module.query(); |
|
| 19816 | } |
|
| 19817 | } |
|
| 19818 | }, |
|
| 19819 | ||
| 19820 | decode: { |
|
| 19821 | json: function(response) { |
|
| 19822 | if(response !== undefined && typeof response == 'string') { |
|
| 19823 | try { |
|
| 19824 | response = JSON.parse(response); |
|
| 19825 | } |
|
| 19826 | catch(e) { |
|
| 19827 | // isnt json string |
|
| 19828 | } |
|
| 19829 | } |
|
| 19830 | return response; |
|
| 19831 | } |
|
| 19832 | }, |
|
| 19833 | ||
| 19834 | read: { |
|
| 19835 | cachedResponse: function(url) { |
|
| 19836 | var |
|
| 19837 | response |
|
| 19838 | ; |
|
| 19839 | if(window.Storage === undefined) { |
|
| 19840 | module.error(error.noStorage); |
|
| 19841 | return; |
|
| 19842 | } |
|
| 19843 | response = sessionStorage.getItem(url); |
|
| 19844 | module.debug('Using cached response', url, response); |
|
| 19845 | response = module.decode.json(response); |
|
| 19846 | return response; |
|
| 19847 | } |
|
| 19848 | }, |
|
| 19849 | write: { |
|
| 19850 | cachedResponse: function(url, response) { |
|
| 19851 | if(response && response === '') { |
|
| 19852 | module.debug('Response empty, not caching', response); |
|
| 19853 | return; |
|
| 19854 | } |
|
| 19855 | if(window.Storage === undefined) { |
|
| 19856 | module.error(error.noStorage); |
|
| 19857 | return; |
|
| 19858 | } |
|
| 19859 | if( $.isPlainObject(response) ) { |
|
| 19860 | response = JSON.stringify(response); |
|
| 19861 | } |
|
| 19862 | sessionStorage.setItem(url, response); |
|
| 19863 | module.verbose('Storing cached response for url', url, response); |
|
| 19864 | } |
|
| 19865 | }, |
|
| 19866 | ||
| 19867 | query: function() { |
|
| 19868 | ||
| 19869 | if(module.is.disabled()) { |
|
| 19870 | module.debug('Element is disabled API request aborted'); |
|
| 19871 | return; |
|
| 19872 | } |
|
| 19873 | ||
| 19874 | if(module.is.loading()) { |
|
| 19875 | if(settings.interruptRequests) { |
|
| 19876 | module.debug('Interrupting previous request'); |
|
| 19877 | module.abort(); |
|
| 19878 | } |
|
| 19879 | else { |
|
| 19880 | module.debug('Cancelling request, previous request is still pending'); |
|
| 19881 | return; |
|
| 19882 | } |
|
| 19883 | } |
|
| 19884 | ||
| 19885 | // pass element metadata to url (value, text) |
|
| 19886 | if(settings.defaultData) { |
|
| 19887 | $.extend(true, settings.urlData, module.get.defaultData()); |
|
| 19888 | } |
|
| 19889 | ||
| 19890 | // Add form content |
|
| 19891 | if(settings.serializeForm) { |
|
| 19892 | settings.data = module.add.formData(settings.data); |
|
| 19893 | } |
|
| 19894 | ||
| 19895 | // call beforesend and get any settings changes |
|
| 19896 | requestSettings = module.get.settings(); |
|
| 19897 | ||
| 19898 | // check if before send cancelled request |
|
| 19899 | if(requestSettings === false) { |
|
| 19900 | module.cancelled = true; |
|
| 19901 | module.error(error.beforeSend); |
|
| 19902 | return; |
|
| 19903 | } |
|
| 19904 | else { |
|
| 19905 | module.cancelled = false; |
|
| 19906 | } |
|
| 19907 | ||
| 19908 | // get url |
|
| 19909 | url = module.get.templatedURL(); |
|
| 19910 | ||
| 19911 | if(!url && !module.is.mocked()) { |
|
| 19912 | module.error(error.missingURL); |
|
| 19913 | return; |
|
| 19914 | } |
|
| 19915 | ||
| 19916 | // replace variables |
|
| 19917 | url = module.add.urlData( url ); |
|
| 19918 | // missing url parameters |
|
| 19919 | if( !url && !module.is.mocked()) { |
|
| 19920 | return; |
|
| 19921 | } |
|
| 19922 | ||
| 19923 | requestSettings.url = settings.base + url; |
|
| 19924 | ||
| 19925 | // look for jQuery ajax parameters in settings |
|
| 19926 | ajaxSettings = $.extend(true, {}, settings, { |
|
| 19927 | type : settings.method || settings.type, |
|
| 19928 | data : data, |
|
| 19929 | url : settings.base + url, |
|
| 19930 | beforeSend : settings.beforeXHR, |
|
| 19931 | success : function() {}, |
|
| 19932 | failure : function() {}, |
|
| 19933 | complete : function() {} |
|
| 19934 | }); |
|
| 19935 | ||
| 19936 | module.debug('Querying URL', ajaxSettings.url); |
|
| 19937 | module.verbose('Using AJAX settings', ajaxSettings); |
|
| 19938 | if(settings.cache === 'local' && module.read.cachedResponse(url)) { |
|
| 19939 | module.debug('Response returned from local cache'); |
|
| 19940 | module.request = module.create.request(); |
|
| 19941 | module.request.resolveWith(context, [ module.read.cachedResponse(url) ]); |
|
| 19942 | return; |
|
| 19943 | } |
|
| 19944 | ||
| 19945 | if( !settings.throttle ) { |
|
| 19946 | module.debug('Sending request', data, ajaxSettings.method); |
|
| 19947 | module.send.request(); |
|
| 19948 | } |
|
| 19949 | else { |
|
| 19950 | if(!settings.throttleFirstRequest && !module.timer) { |
|
| 19951 | module.debug('Sending request', data, ajaxSettings.method); |
|
| 19952 | module.send.request(); |
|
| 19953 | module.timer = setTimeout(function(){}, settings.throttle); |
|
| 19954 | } |
|
| 19955 | else { |
|
| 19956 | module.debug('Throttling request', settings.throttle); |
|
| 19957 | clearTimeout(module.timer); |
|
| 19958 | module.timer = setTimeout(function() { |
|
| 19959 | if(module.timer) { |
|
| 19960 | delete module.timer; |
|
| 19961 | } |
|
| 19962 | module.debug('Sending throttled request', data, ajaxSettings.method); |
|
| 19963 | module.send.request(); |
|
| 19964 | }, settings.throttle); |
|
| 19965 | } |
|
| 19966 | } |
|
| 19967 | ||
| 19968 | }, |
|
| 19969 | ||
| 19970 | should: { |
|
| 19971 | removeError: function() { |
|
| 19972 | return ( settings.hideError === true || (settings.hideError === 'auto' && !module.is.form()) ); |
|
| 19973 | } |
|
| 19974 | }, |
|
| 19975 | ||
| 19976 | is: { |
|
| 19977 | disabled: function() { |
|
| 19978 | return ($module.filter(selector.disabled).length > 0); |
|
| 19979 | }, |
|
| 19980 | expectingJSON: function() { |
|
| 19981 | return settings.dataType === 'json' || settings.dataType === 'jsonp'; |
|
| 19982 | }, |
|
| 19983 | form: function() { |
|
| 19984 | return $module.is('form') || $context.is('form'); |
|
| 19985 | }, |
|
| 19986 | mocked: function() { |
|
| 19987 | return (settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync); |
|
| 19988 | }, |
|
| 19989 | input: function() { |
|
| 19990 | return $module.is('input'); |
|
| 19991 | }, |
|
| 19992 | loading: function() { |
|
| 19993 | return (module.request) |
|
| 19994 | ? (module.request.state() == 'pending') |
|
| 19995 | : false |
|
| 19996 | ; |
|
| 19997 | }, |
|
| 19998 | abortedRequest: function(xhr) { |
|
| 19999 | if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) { |
|
| 20000 | module.verbose('XHR request determined to be aborted'); |
|
| 20001 | return true; |
|
| 20002 | } |
|
| 20003 | else { |
|
| 20004 | module.verbose('XHR request was not aborted'); |
|
| 20005 | return false; |
|
| 20006 | } |
|
| 20007 | }, |
|
| 20008 | validResponse: function(response) { |
|
| 20009 | if( (!module.is.expectingJSON()) || !$.isFunction(settings.successTest) ) { |
|
| 20010 | module.verbose('Response is not JSON, skipping validation', settings.successTest, response); |
|
| 20011 | return true; |
|
| 20012 | } |
|
| 20013 | module.debug('Checking JSON returned success', settings.successTest, response); |
|
| 20014 | if( settings.successTest(response) ) { |
|
| 20015 | module.debug('Response passed success test', response); |
|
| 20016 | return true; |
|
| 20017 | } |
|
| 20018 | else { |
|
| 20019 | module.debug('Response failed success test', response); |
|
| 20020 | return false; |
|
| 20021 | } |
|
| 20022 | } |
|
| 20023 | }, |
|
| 20024 | ||
| 20025 | was: { |
|
| 20026 | cancelled: function() { |
|
| 20027 | return (module.cancelled || false); |
|
| 20028 | }, |
|
| 20029 | succesful: function() { |
|
| 20030 | return (module.request && module.request.state() == 'resolved'); |
|
| 20031 | }, |
|
| 20032 | failure: function() { |
|
| 20033 | return (module.request && module.request.state() == 'rejected'); |
|
| 20034 | }, |
|
| 20035 | complete: function() { |
|
| 20036 | return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') ); |
|
| 20037 | } |
|
| 20038 | }, |
|
| 20039 | ||
| 20040 | add: { |
|
| 20041 | urlData: function(url, urlData) { |
|
| 20042 | var |
|
| 20043 | requiredVariables, |
|
| 20044 | optionalVariables |
|
| 20045 | ; |
|
| 20046 | if(url) { |
|
| 20047 | requiredVariables = url.match(settings.regExp.required); |
|
| 20048 | optionalVariables = url.match(settings.regExp.optional); |
|
| 20049 | urlData = urlData || settings.urlData; |
|
| 20050 | if(requiredVariables) { |
|
| 20051 | module.debug('Looking for required URL variables', requiredVariables); |
|
| 20052 | $.each(requiredVariables, function(index, templatedString) { |
|
| 20053 | var |
|
| 20054 | // allow legacy {$var} style |
|
| 20055 | variable = (templatedString.indexOf('$') !== -1) |
|
| 20056 | ? templatedString.substr(2, templatedString.length - 3) |
|
| 20057 | : templatedString.substr(1, templatedString.length - 2), |
|
| 20058 | value = ($.isPlainObject(urlData) && urlData[variable] !== undefined) |
|
| 20059 | ? urlData[variable] |
|
| 20060 | : ($module.data(variable) !== undefined) |
|
| 20061 | ? $module.data(variable) |
|
| 20062 | : ($context.data(variable) !== undefined) |
|
| 20063 | ? $context.data(variable) |
|
| 20064 | : urlData[variable] |
|
| 20065 | ; |
|
| 20066 | // remove value |
|
| 20067 | if(value === undefined) { |
|
| 20068 | module.error(error.requiredParameter, variable, url); |
|
| 20069 | url = false; |
|
| 20070 | return false; |
|
| 20071 | } |
|
| 20072 | else { |
|
| 20073 | module.verbose('Found required variable', variable, value); |
|
| 20074 | value = (settings.encodeParameters) |
|
| 20075 | ? module.get.urlEncodedValue(value) |
|
| 20076 | : value |
|
| 20077 | ; |
|
| 20078 | url = url.replace(templatedString, value); |
|
| 20079 | } |
|
| 20080 | }); |
|
| 20081 | } |
|
| 20082 | if(optionalVariables) { |
|
| 20083 | module.debug('Looking for optional URL variables', requiredVariables); |
|
| 20084 | $.each(optionalVariables, function(index, templatedString) { |
|
| 20085 | var |
|
| 20086 | // allow legacy {/$var} style |
|
| 20087 | variable = (templatedString.indexOf('$') !== -1) |
|
| 20088 | ? templatedString.substr(3, templatedString.length - 4) |
|
| 20089 | : templatedString.substr(2, templatedString.length - 3), |
|
| 20090 | value = ($.isPlainObject(urlData) && urlData[variable] !== undefined) |
|
| 20091 | ? urlData[variable] |
|
| 20092 | : ($module.data(variable) !== undefined) |
|
| 20093 | ? $module.data(variable) |
|
| 20094 | : ($context.data(variable) !== undefined) |
|
| 20095 | ? $context.data(variable) |
|
| 20096 | : urlData[variable] |
|
| 20097 | ; |
|
| 20098 | // optional replacement |
|
| 20099 | if(value !== undefined) { |
|
| 20100 | module.verbose('Optional variable Found', variable, value); |
|
| 20101 | url = url.replace(templatedString, value); |
|
| 20102 | } |
|
| 20103 | else { |
|
| 20104 | module.verbose('Optional variable not found', variable); |
|
| 20105 | // remove preceding slash if set |
|
| 20106 | if(url.indexOf('/' + templatedString) !== -1) { |
|
| 20107 | url = url.replace('/' + templatedString, ''); |
|
| 20108 | } |
|
| 20109 | else { |
|
| 20110 | url = url.replace(templatedString, ''); |
|
| 20111 | } |
|
| 20112 | } |
|
| 20113 | }); |
|
| 20114 | } |
|
| 20115 | } |
|
| 20116 | return url; |
|
| 20117 | }, |
|
| 20118 | formData: function(data) { |
|
| 20119 | var |
|
| 20120 | canSerialize = ($.fn.serializeObject !== undefined), |
|
| 20121 | formData = (canSerialize) |
|
| 20122 | ? $form.serializeObject() |
|
| 20123 | : $form.serialize(), |
|
| 20124 | hasOtherData |
|
| 20125 | ; |
|
| 20126 | data = data || settings.data; |
|
| 20127 | hasOtherData = $.isPlainObject(data); |
|
| 20128 | ||
| 20129 | if(hasOtherData) { |
|
| 20130 | if(canSerialize) { |
|
| 20131 | module.debug('Extending existing data with form data', data, formData); |
|
| 20132 | data = $.extend(true, {}, data, formData); |
|
| 20133 | } |
|
| 20134 | else { |
|
| 20135 | module.error(error.missingSerialize); |
|
| 20136 | module.debug('Cant extend data. Replacing data with form data', data, formData); |
|
| 20137 | data = formData; |
|
| 20138 | } |
|
| 20139 | } |
|
| 20140 | else { |
|
| 20141 | module.debug('Adding form data', formData); |
|
| 20142 | data = formData; |
|
| 20143 | } |
|
| 20144 | return data; |
|
| 20145 | } |
|
| 20146 | }, |
|
| 20147 | ||
| 20148 | send: { |
|
| 20149 | request: function() { |
|
| 20150 | module.set.loading(); |
|
| 20151 | module.request = module.create.request(); |
|
| 20152 | if( module.is.mocked() ) { |
|
| 20153 | module.mockedXHR = module.create.mockedXHR(); |
|
| 20154 | } |
|
| 20155 | else { |
|
| 20156 | module.xhr = module.create.xhr(); |
|
| 20157 | } |
|
| 20158 | settings.onRequest.call(context, module.request, module.xhr); |
|
| 20159 | } |
|
| 20160 | }, |
|
| 20161 | ||
| 20162 | event: { |
|
| 20163 | trigger: function(event) { |
|
| 20164 | module.query(); |
|
| 20165 | if(event.type == 'submit' || event.type == 'click') { |
|
| 20166 | event.preventDefault(); |
|
| 20167 | } |
|
| 20168 | }, |
|
| 20169 | xhr: { |
|
| 20170 | always: function() { |
|
| 20171 | // nothing special |
|
| 20172 | }, |
|
| 20173 | done: function(response, textStatus, xhr) { |
|
| 20174 | var |
|
| 20175 | context = this, |
|
| 20176 | elapsedTime = (new Date().getTime() - requestStartTime), |
|
| 20177 | timeLeft = (settings.loadingDuration - elapsedTime), |
|
| 20178 | translatedResponse = ( $.isFunction(settings.onResponse) ) |
|
| 20179 | ? module.is.expectingJSON() |
|
| 20180 | ? settings.onResponse.call(context, $.extend(true, {}, response)) |
|
| 20181 | : settings.onResponse.call(context, response) |
|
| 20182 | : false |
|
| 20183 | ; |
|
| 20184 | timeLeft = (timeLeft > 0) |
|
| 20185 | ? timeLeft |
|
| 20186 | : 0 |
|
| 20187 | ; |
|
| 20188 | if(translatedResponse) { |
|
| 20189 | module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response); |
|
| 20190 | response = translatedResponse; |
|
| 20191 | } |
|
| 20192 | if(timeLeft > 0) { |
|
| 20193 | module.debug('Response completed early delaying state change by', timeLeft); |
|
| 20194 | } |
|
| 20195 | setTimeout(function() { |
|
| 20196 | if( module.is.validResponse(response) ) { |
|
| 20197 | module.request.resolveWith(context, [response, xhr]); |
|
| 20198 | } |
|
| 20199 | else { |
|
| 20200 | module.request.rejectWith(context, [xhr, 'invalid']); |
|
| 20201 | } |
|
| 20202 | }, timeLeft); |
|
| 20203 | }, |
|
| 20204 | fail: function(xhr, status, httpMessage) { |
|
| 20205 | var |
|
| 20206 | context = this, |
|
| 20207 | elapsedTime = (new Date().getTime() - requestStartTime), |
|
| 20208 | timeLeft = (settings.loadingDuration - elapsedTime) |
|
| 20209 | ; |
|
| 20210 | timeLeft = (timeLeft > 0) |
|
| 20211 | ? timeLeft |
|
| 20212 | : 0 |
|
| 20213 | ; |
|
| 20214 | if(timeLeft > 0) { |
|
| 20215 | module.debug('Response completed early delaying state change by', timeLeft); |
|
| 20216 | } |
|
| 20217 | setTimeout(function() { |
|
| 20218 | if( module.is.abortedRequest(xhr) ) { |
|
| 20219 | module.request.rejectWith(context, [xhr, 'aborted', httpMessage]); |
|
| 20220 | } |
|
| 20221 | else { |
|
| 20222 | module.request.rejectWith(context, [xhr, 'error', status, httpMessage]); |
|
| 20223 | } |
|
| 20224 | }, timeLeft); |
|
| 20225 | } |
|
| 20226 | }, |
|
| 20227 | request: { |
|
| 20228 | done: function(response, xhr) { |
|
| 20229 | module.debug('Successful API Response', response); |
|
| 20230 | if(settings.cache === 'local' && url) { |
|
| 20231 | module.write.cachedResponse(url, response); |
|
| 20232 | module.debug('Saving server response locally', module.cache); |
|
| 20233 | } |
|
| 20234 | settings.onSuccess.call(context, response, $module, xhr); |
|
| 20235 | }, |
|
| 20236 | complete: function(firstParameter, secondParameter) { |
|
| 20237 | var |
|
| 20238 | xhr, |
|
| 20239 | response |
|
| 20240 | ; |
|
| 20241 | // have to guess callback parameters based on request success |
|
| 20242 | if( module.was.succesful() ) { |
|
| 20243 | response = firstParameter; |
|
| 20244 | xhr = secondParameter; |
|
| 20245 | } |
|
| 20246 | else { |
|
| 20247 | xhr = firstParameter; |
|
| 20248 | response = module.get.responseFromXHR(xhr); |
|
| 20249 | } |
|
| 20250 | module.remove.loading(); |
|
| 20251 | settings.onComplete.call(context, response, $module, xhr); |
|
| 20252 | }, |
|
| 20253 | fail: function(xhr, status, httpMessage) { |
|
| 20254 | var |
|
| 20255 | // pull response from xhr if available |
|
| 20256 | response = module.get.responseFromXHR(xhr), |
|
| 20257 | errorMessage = module.get.errorFromRequest(response, status, httpMessage) |
|
| 20258 | ; |
|
| 20259 | if(status == 'aborted') { |
|
| 20260 | module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage); |
|
| 20261 | settings.onAbort.call(context, status, $module, xhr); |
|
| 20262 | return true; |
|
| 20263 | } |
|
| 20264 | else if(status == 'invalid') { |
|
| 20265 | module.debug('JSON did not pass success test. A server-side error has most likely occurred', response); |
|
| 20266 | } |
|
| 20267 | else if(status == 'error') { |
|
| 20268 | if(xhr !== undefined) { |
|
| 20269 | module.debug('XHR produced a server error', status, httpMessage); |
|
| 20270 | // make sure we have an error to display to console |
|
| 20271 | if( xhr.status != 200 && httpMessage !== undefined && httpMessage !== '') { |
|
| 20272 | module.error(error.statusMessage + httpMessage, ajaxSettings.url); |
|
| 20273 | } |
|
| 20274 | settings.onError.call(context, errorMessage, $module, xhr); |
|
| 20275 | } |
|
| 20276 | } |
|
| 20277 | ||
| 20278 | if(settings.errorDuration && status !== 'aborted') { |
|
| 20279 | module.debug('Adding error state'); |
|
| 20280 | module.set.error(); |
|
| 20281 | if( module.should.removeError() ) { |
|
| 20282 | setTimeout(module.remove.error, settings.errorDuration); |
|
| 20283 | } |
|
| 20284 | } |
|
| 20285 | module.debug('API Request failed', errorMessage, xhr); |
|
| 20286 | settings.onFailure.call(context, response, $module, xhr); |
|
| 20287 | } |
|
| 20288 | } |
|
| 20289 | }, |
|
| 20290 | ||
| 20291 | create: { |
|
| 20292 | ||
| 20293 | request: function() { |
|
| 20294 | // api request promise |
|
| 20295 | return $.Deferred() |
|
| 20296 | .always(module.event.request.complete) |
|
| 20297 | .done(module.event.request.done) |
|
| 20298 | .fail(module.event.request.fail) |
|
| 20299 | ; |
|
| 20300 | }, |
|
| 20301 | ||
| 20302 | mockedXHR: function () { |
|
| 20303 | var |
|
| 20304 | // xhr does not simulate these properties of xhr but must return them |
|
| 20305 | textStatus = false, |
|
| 20306 | status = false, |
|
| 20307 | httpMessage = false, |
|
| 20308 | responder = settings.mockResponse || settings.response, |
|
| 20309 | asyncResponder = settings.mockResponseAsync || settings.responseAsync, |
|
| 20310 | asyncCallback, |
|
| 20311 | response, |
|
| 20312 | mockedXHR |
|
| 20313 | ; |
|
| 20314 | ||
| 20315 | mockedXHR = $.Deferred() |
|
| 20316 | .always(module.event.xhr.complete) |
|
| 20317 | .done(module.event.xhr.done) |
|
| 20318 | .fail(module.event.xhr.fail) |
|
| 20319 | ; |
|
| 20320 | ||
| 20321 | if(responder) { |
|
| 20322 | if( $.isFunction(responder) ) { |
|
| 20323 | module.debug('Using specified synchronous callback', responder); |
|
| 20324 | response = responder.call(context, requestSettings); |
|
| 20325 | } |
|
| 20326 | else { |
|
| 20327 | module.debug('Using settings specified response', responder); |
|
| 20328 | response = responder; |
|
| 20329 | } |
|
| 20330 | // simulating response |
|
| 20331 | mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); |
|
| 20332 | } |
|
| 20333 | else if( $.isFunction(asyncResponder) ) { |
|
| 20334 | asyncCallback = function(response) { |
|
| 20335 | module.debug('Async callback returned response', response); |
|
| 20336 | ||
| 20337 | if(response) { |
|
| 20338 | mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); |
|
| 20339 | } |
|
| 20340 | else { |
|
| 20341 | mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]); |
|
| 20342 | } |
|
| 20343 | }; |
|
| 20344 | module.debug('Using specified async response callback', asyncResponder); |
|
| 20345 | asyncResponder.call(context, requestSettings, asyncCallback); |
|
| 20346 | } |
|
| 20347 | return mockedXHR; |
|
| 20348 | }, |
|
| 20349 | ||
| 20350 | xhr: function() { |
|
| 20351 | var |
|
| 20352 | xhr |
|
| 20353 | ; |
|
| 20354 | // ajax request promise |
|
| 20355 | xhr = $.ajax(ajaxSettings) |
|
| 20356 | .always(module.event.xhr.always) |
|
| 20357 | .done(module.event.xhr.done) |
|
| 20358 | .fail(module.event.xhr.fail) |
|
| 20359 | ; |
|
| 20360 | module.verbose('Created server request', xhr, ajaxSettings); |
|
| 20361 | return xhr; |
|
| 20362 | } |
|
| 20363 | }, |
|
| 20364 | ||
| 20365 | set: { |
|
| 20366 | error: function() { |
|
| 20367 | module.verbose('Adding error state to element', $context); |
|
| 20368 | $context.addClass(className.error); |
|
| 20369 | }, |
|
| 20370 | loading: function() { |
|
| 20371 | module.verbose('Adding loading state to element', $context); |
|
| 20372 | $context.addClass(className.loading); |
|
| 20373 | requestStartTime = new Date().getTime(); |
|
| 20374 | } |
|
| 20375 | }, |
|
| 20376 | ||
| 20377 | remove: { |
|
| 20378 | error: function() { |
|
| 20379 | module.verbose('Removing error state from element', $context); |
|
| 20380 | $context.removeClass(className.error); |
|
| 20381 | }, |
|
| 20382 | loading: function() { |
|
| 20383 | module.verbose('Removing loading state from element', $context); |
|
| 20384 | $context.removeClass(className.loading); |
|
| 20385 | } |
|
| 20386 | }, |
|
| 20387 | ||
| 20388 | get: { |
|
| 20389 | responseFromXHR: function(xhr) { |
|
| 20390 | return $.isPlainObject(xhr) |
|
| 20391 | ? (module.is.expectingJSON()) |
|
| 20392 | ? module.decode.json(xhr.responseText) |
|
| 20393 | : xhr.responseText |
|
| 20394 | : false |
|
| 20395 | ; |
|
| 20396 | }, |
|
| 20397 | errorFromRequest: function(response, status, httpMessage) { |
|
| 20398 | return ($.isPlainObject(response) && response.error !== undefined) |
|
| 20399 | ? response.error // use json error message |
|
| 20400 | : (settings.error[status] !== undefined) // use server error message |
|
| 20401 | ? settings.error[status] |
|
| 20402 | : httpMessage |
|
| 20403 | ; |
|
| 20404 | }, |
|
| 20405 | request: function() { |
|
| 20406 | return module.request || false; |
|
| 20407 | }, |
|
| 20408 | xhr: function() { |
|
| 20409 | return module.xhr || false; |
|
| 20410 | }, |
|
| 20411 | settings: function() { |
|
| 20412 | var |
|
| 20413 | runSettings |
|
| 20414 | ; |
|
| 20415 | runSettings = settings.beforeSend.call(context, settings); |
|
| 20416 | if(runSettings) { |
|
| 20417 | if(runSettings.success !== undefined) { |
|
| 20418 | module.debug('Legacy success callback detected', runSettings); |
|
| 20419 | module.error(error.legacyParameters, runSettings.success); |
|
| 20420 | runSettings.onSuccess = runSettings.success; |
|
| 20421 | } |
|
| 20422 | if(runSettings.failure !== undefined) { |
|
| 20423 | module.debug('Legacy failure callback detected', runSettings); |
|
| 20424 | module.error(error.legacyParameters, runSettings.failure); |
|
| 20425 | runSettings.onFailure = runSettings.failure; |
|
| 20426 | } |
|
| 20427 | if(runSettings.complete !== undefined) { |
|
| 20428 | module.debug('Legacy complete callback detected', runSettings); |
|
| 20429 | module.error(error.legacyParameters, runSettings.complete); |
|
| 20430 | runSettings.onComplete = runSettings.complete; |
|
| 20431 | } |
|
| 20432 | } |
|
| 20433 | if(runSettings === undefined) { |
|
| 20434 | module.error(error.noReturnedValue); |
|
| 20435 | } |
|
| 20436 | if(runSettings === false) { |
|
| 20437 | return runSettings; |
|
| 20438 | } |
|
| 20439 | return (runSettings !== undefined) |
|
| 20440 | ? $.extend(true, {}, runSettings) |
|
| 20441 | : $.extend(true, {}, settings) |
|
| 20442 | ; |
|
| 20443 | }, |
|
| 20444 | urlEncodedValue: function(value) { |
|
| 20445 | var |
|
| 20446 | decodedValue = window.decodeURIComponent(value), |
|
| 20447 | encodedValue = window.encodeURIComponent(value), |
|
| 20448 | alreadyEncoded = (decodedValue !== value) |
|
| 20449 | ; |
|
| 20450 | if(alreadyEncoded) { |
|
| 20451 | module.debug('URL value is already encoded, avoiding double encoding', value); |
|
| 20452 | return value; |
|
| 20453 | } |
|
| 20454 | module.verbose('Encoding value using encodeURIComponent', value, encodedValue); |
|
| 20455 | return encodedValue; |
|
| 20456 | }, |
|
| 20457 | defaultData: function() { |
|
| 20458 | var |
|
| 20459 | data = {} |
|
| 20460 | ; |
|
| 20461 | if( !$.isWindow(element) ) { |
|
| 20462 | if( module.is.input() ) { |
|
| 20463 | data.value = $module.val(); |
|
| 20464 | } |
|
| 20465 | else if( module.is.form() ) { |
|
| 20466 | ||
| 20467 | } |
|
| 20468 | else { |
|
| 20469 | data.text = $module.text(); |
|
| 20470 | } |
|
| 20471 | } |
|
| 20472 | return data; |
|
| 20473 | }, |
|
| 20474 | event: function() { |
|
| 20475 | if( $.isWindow(element) || settings.on == 'now' ) { |
|
| 20476 | module.debug('API called without element, no events attached'); |
|
| 20477 | return false; |
|
| 20478 | } |
|
| 20479 | else if(settings.on == 'auto') { |
|
| 20480 | if( $module.is('input') ) { |
|
| 20481 | return (element.oninput !== undefined) |
|
| 20482 | ? 'input' |
|
| 20483 | : (element.onpropertychange !== undefined) |
|
| 20484 | ? 'propertychange' |
|
| 20485 | : 'keyup' |
|
| 20486 | ; |
|
| 20487 | } |
|
| 20488 | else if( $module.is('form') ) { |
|
| 20489 | return 'submit'; |
|
| 20490 | } |
|
| 20491 | else { |
|
| 20492 | return 'click'; |
|
| 20493 | } |
|
| 20494 | } |
|
| 20495 | else { |
|
| 20496 | return settings.on; |
|
| 20497 | } |
|
| 20498 | }, |
|
| 20499 | templatedURL: function(action) { |
|
| 20500 | action = action || $module.data(metadata.action) || settings.action || false; |
|
| 20501 | url = $module.data(metadata.url) || settings.url || false; |
|
| 20502 | if(url) { |
|
| 20503 | module.debug('Using specified url', url); |
|
| 20504 | return url; |
|
| 20505 | } |
|
| 20506 | if(action) { |
|
| 20507 | module.debug('Looking up url for action', action, settings.api); |
|
| 20508 | if(settings.api[action] === undefined && !module.is.mocked()) { |
|
| 20509 | module.error(error.missingAction, settings.action, settings.api); |
|
| 20510 | return; |
|
| 20511 | } |
|
| 20512 | url = settings.api[action]; |
|
| 20513 | } |
|
| 20514 | else if( module.is.form() ) { |
|
| 20515 | url = $module.attr('action') || $context.attr('action') || false; |
|
| 20516 | module.debug('No url or action specified, defaulting to form action', url); |
|
| 20517 | } |
|
| 20518 | return url; |
|
| 20519 | } |
|
| 20520 | }, |
|
| 20521 | ||
| 20522 | abort: function() { |
|
| 20523 | var |
|
| 20524 | xhr = module.get.xhr() |
|
| 20525 | ; |
|
| 20526 | if( xhr && xhr.state() !== 'resolved') { |
|
| 20527 | module.debug('Cancelling API request'); |
|
| 20528 | xhr.abort(); |
|
| 20529 | } |
|
| 20530 | }, |
|
| 20531 | ||
| 20532 | // reset state |
|
| 20533 | reset: function() { |
|
| 20534 | module.remove.error(); |
|
| 20535 | module.remove.loading(); |
|
| 20536 | }, |
|
| 20537 | ||
| 20538 | setting: function(name, value) { |
|
| 20539 | module.debug('Changing setting', name, value); |
|
| 20540 | if( $.isPlainObject(name) ) { |
|
| 20541 | $.extend(true, settings, name); |
|
| 20542 | } |
|
| 20543 | else if(value !== undefined) { |
|
| 20544 | if($.isPlainObject(settings[name])) { |
|
| 20545 | $.extend(true, settings[name], value); |
|
| 20546 | } |
|
| 20547 | else { |
|
| 20548 | settings[name] = value; |
|
| 20549 | } |
|
| 20550 | } |
|
| 20551 | else { |
|
| 20552 | return settings[name]; |
|
| 20553 | } |
|
| 20554 | }, |
|
| 20555 | internal: function(name, value) { |
|
| 20556 | if( $.isPlainObject(name) ) { |
|
| 20557 | $.extend(true, module, name); |
|
| 20558 | } |
|
| 20559 | else if(value !== undefined) { |
|
| 20560 | module[name] = value; |
|
| 20561 | } |
|
| 20562 | else { |
|
| 20563 | return module[name]; |
|
| 20564 | } |
|
| 20565 | }, |
|
| 20566 | debug: function() { |
|
| 20567 | if(!settings.silent && settings.debug) { |
|
| 20568 | if(settings.performance) { |
|
| 20569 | module.performance.log(arguments); |
|
| 20570 | } |
|
| 20571 | else { |
|
| 20572 | module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 20573 | module.debug.apply(console, arguments); |
|
| 20574 | } |
|
| 20575 | } |
|
| 20576 | }, |
|
| 20577 | verbose: function() { |
|
| 20578 | if(!settings.silent && settings.verbose && settings.debug) { |
|
| 20579 | if(settings.performance) { |
|
| 20580 | module.performance.log(arguments); |
|
| 20581 | } |
|
| 20582 | else { |
|
| 20583 | module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 20584 | module.verbose.apply(console, arguments); |
|
| 20585 | } |
|
| 20586 | } |
|
| 20587 | }, |
|
| 20588 | error: function() { |
|
| 20589 | if(!settings.silent) { |
|
| 20590 | module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); |
|
| 20591 | module.error.apply(console, arguments); |
|
| 20592 | } |
|
| 20593 | }, |
|
| 20594 | performance: { |
|
| 20595 | log: function(message) { |
|
| 20596 | var |
|
| 20597 | currentTime, |
|
| 20598 | executionTime, |
|
| 20599 | previousTime |
|
| 20600 | ; |
|
| 20601 | if(settings.performance) { |
|
| 20602 | currentTime = new Date().getTime(); |
|
| 20603 | previousTime = time || currentTime; |
|
| 20604 | executionTime = currentTime - previousTime; |
|
| 20605 | time = currentTime; |
|
| 20606 | performance.push({ |
|
| 20607 | 'Name' : message[0], |
|
| 20608 | 'Arguments' : [].slice.call(message, 1) || '', |
|
| 20609 | //'Element' : element, |
|
| 20610 | 'Execution Time' : executionTime |
|
| 20611 | }); |
|
| 20612 | } |
|
| 20613 | clearTimeout(module.performance.timer); |
|
| 20614 | module.performance.timer = setTimeout(module.performance.display, 500); |
|
| 20615 | }, |
|
| 20616 | display: function() { |
|
| 20617 | var |
|
| 20618 | title = settings.name + ':', |
|
| 20619 | totalTime = 0 |
|
| 20620 | ; |
|
| 20621 | time = false; |
|
| 20622 | clearTimeout(module.performance.timer); |
|
| 20623 | $.each(performance, function(index, data) { |
|
| 20624 | totalTime += data['Execution Time']; |
|
| 20625 | }); |
|
| 20626 | title += ' ' + totalTime + 'ms'; |
|
| 20627 | if(moduleSelector) { |
|
| 20628 | title += ' \'' + moduleSelector + '\''; |
|
| 20629 | } |
|
| 20630 | if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { |
|
| 20631 | console.groupCollapsed(title); |
|
| 20632 | if(console.table) { |
|
| 20633 | console.table(performance); |
|
| 20634 | } |
|
| 20635 | else { |
|
| 20636 | $.each(performance, function(index, data) { |
|
| 20637 | console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); |
|
| 20638 | }); |
|
| 20639 | } |
|
| 20640 | console.groupEnd(); |
|
| 20641 | } |
|
| 20642 | performance = []; |
|
| 20643 | } |
|
| 20644 | }, |
|
| 20645 | invoke: function(query, passedArguments, context) { |
|
| 20646 | var |
|
| 20647 | object = instance, |
|
| 20648 | maxDepth, |
|
| 20649 | found, |
|
| 20650 | response |
|
| 20651 | ; |
|
| 20652 | passedArguments = passedArguments || queryArguments; |
|
| 20653 | context = element || context; |
|
| 20654 | if(typeof query == 'string' && object !== undefined) { |
|
| 20655 | query = query.split(/[\. ]/); |
|
| 20656 | maxDepth = query.length - 1; |
|
| 20657 | $.each(query, function(depth, value) { |
|
| 20658 | var camelCaseValue = (depth != maxDepth) |
|
| 20659 | ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) |
|
| 20660 | : query |
|
| 20661 | ; |
|
| 20662 | if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { |
|
| 20663 | object = object[camelCaseValue]; |
|
| 20664 | } |
|
| 20665 | else if( object[camelCaseValue] !== undefined ) { |
|
| 20666 | found = object[camelCaseValue]; |
|
| 20667 | return false; |
|
| 20668 | } |
|
| 20669 | else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { |
|
| 20670 | object = object[value]; |
|
| 20671 | } |
|
| 20672 | else if( object[value] !== undefined ) { |
|
| 20673 | found = object[value]; |
|
| 20674 | return false; |
|
| 20675 | } |
|
| 20676 | else { |
|
| 20677 | module.error(error.method, query); |
|
| 20678 | return false; |
|
| 20679 | } |
|
| 20680 | }); |
|
| 20681 | } |
|
| 20682 | if ( $.isFunction( found ) ) { |
|
| 20683 | response = found.apply(context, passedArguments); |
|
| 20684 | } |
|
| 20685 | else if(found !== undefined) { |
|
| 20686 | response = found; |
|
| 20687 | } |
|
| 20688 | if($.isArray(returnedValue)) { |
|
| 20689 | returnedValue.push(response); |
|
| 20690 | } |
|
| 20691 | else if(returnedValue !== undefined) { |
|
| 20692 | returnedValue = [returnedValue, response]; |
|
| 20693 | } |
|
| 20694 | else if(response !== undefined) { |
|
| 20695 | returnedValue = response; |
|
| 20696 | } |
|
| 20697 | return found; |
|
| 20698 | } |
|
| 20699 | }; |
|
| 20700 | ||
| 20701 | if(methodInvoked) { |
|
| 20702 | if(instance === undefined) { |
|
| 20703 | module.initialize(); |
|
| 20704 | } |
|
| 20705 | module.invoke(query); |
|
| 20706 | } |
|
| 20707 | else { |
|
| 20708 | if(instance !== undefined) { |
|
| 20709 | instance.invoke('destroy'); |
|
| 20710 | } |
|
| 20711 | module.initialize(); |
|
| 20712 | } |
|
| 20713 | }) |
|
| 20714 | ; |
|
| 20715 | ||
| 20716 | return (returnedValue !== undefined) |
|
| 20717 | ? returnedValue |
|
| 20718 | : this |
|
| 20719 | ; |
|
| 20720 | }; |
|
| 20721 | ||
| 20722 | $.api.settings = { |
|
| 20723 | ||
| 20724 | name : 'API', |
|
| 20725 | namespace : 'api', |
|
| 20726 | ||
| 20727 | debug : false, |
|
| 20728 | verbose : false, |
|
| 20729 | performance : true, |
|
| 20730 | ||
| 20731 | // object containing all templates endpoints |
|
| 20732 | api : {}, |
|
| 20733 | ||
| 20734 | // whether to cache responses |
|
| 20735 | cache : true, |
|
| 20736 | ||
| 20737 | // whether new requests should abort previous requests |
|
| 20738 | interruptRequests : true, |
|
| 20739 | ||
| 20740 | // event binding |
|
| 20741 | on : 'auto', |
|
| 20742 | ||
| 20743 | // context for applying state classes |
|
| 20744 | stateContext : false, |
|
| 20745 | ||
| 20746 | // duration for loading state |
|
| 20747 | loadingDuration : 0, |
|
| 20748 | ||
| 20749 | // whether to hide errors after a period of time |
|
| 20750 | hideError : 'auto', |
|
| 20751 | ||
| 20752 | // duration for error state |
|
| 20753 | errorDuration : 2000, |
|
| 20754 | ||
| 20755 | // whether parameters should be encoded with encodeURIComponent |
|
| 20756 | encodeParameters : true, |
|
| 20757 | ||
| 20758 | // API action to use |
|
| 20759 | action : false, |
|
| 20760 | ||
| 20761 | // templated URL to use |
|
| 20762 | url : false, |
|
| 20763 | ||
| 20764 | // base URL to apply to all endpoints |
|
| 20765 | base : '', |
|
| 20766 | ||
| 20767 | // data that will |
|
| 20768 | urlData : {}, |
|
| 20769 | ||
| 20770 | // whether to add default data to url data |
|
| 20771 | defaultData : true, |
|
| 20772 | ||
| 20773 | // whether to serialize closest form |
|
| 20774 | serializeForm : false, |
|
| 20775 | ||
| 20776 | // how long to wait before request should occur |
|
| 20777 | throttle : 0, |
|
| 20778 | ||
| 20779 | // whether to throttle first request or only repeated |
|
| 20780 | throttleFirstRequest : true, |
|
| 20781 | ||
| 20782 | // standard ajax settings |
|
| 20783 | method : 'get', |
|
| 20784 | data : {}, |
|
| 20785 | dataType : 'json', |
|
| 20786 | ||
| 20787 | // mock response |
|
| 20788 | mockResponse : false, |
|
| 20789 | mockResponseAsync : false, |
|
| 20790 | ||
| 20791 | // aliases for mock |
|
| 20792 | response : false, |
|
| 20793 | responseAsync : false, |
|
| 20794 | ||
| 20795 | // callbacks before request |
|
| 20796 | beforeSend : function(settings) { return settings; }, |
|
| 20797 | beforeXHR : function(xhr) {}, |
|
| 20798 | onRequest : function(promise, xhr) {}, |
|
| 20799 | ||
| 20800 | // after request |
|
| 20801 | onResponse : false, // function(response) { }, |
|
| 20802 | ||
| 20803 | // response was successful, if JSON passed validation |
|
| 20804 | onSuccess : function(response, $module) {}, |
|
| 20805 | ||
| 20806 | // request finished without aborting |
|
| 20807 | onComplete : function(response, $module) {}, |
|
| 20808 | ||
| 20809 | // failed JSON success test |
|
| 20810 | onFailure : function(response, $module) {}, |
|
| 20811 | ||
| 20812 | // server error |
|
| 20813 | onError : function(errorMessage, $module) {}, |
|
| 20814 | ||
| 20815 | // request aborted |
|
| 20816 | onAbort : function(errorMessage, $module) {}, |
|
| 20817 | ||
| 20818 | successTest : false, |
|
| 20819 | ||
| 20820 | // errors |
|
| 20821 | error : { |
|
| 20822 | beforeSend : 'The before send function has aborted the request', |
|
| 20823 | error : 'There was an error with your request', |
|
| 20824 | exitConditions : 'API Request Aborted. Exit conditions met', |
|
| 20825 | JSONParse : 'JSON could not be parsed during error handling', |
|
| 20826 | legacyParameters : 'You are using legacy API success callback names', |
|
| 20827 | method : 'The method you called is not defined', |
|
| 20828 | missingAction : 'API action used but no url was defined', |
|
| 20829 | missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object', |
|
| 20830 | missingURL : 'No URL specified for api event', |
|
| 20831 | noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.', |
|
| 20832 | noStorage : 'Caching responses locally requires session storage', |
|
| 20833 | parseError : 'There was an error parsing your request', |
|
| 20834 | requiredParameter : 'Missing a required URL parameter: ', |
|
| 20835 | statusMessage : 'Server gave an error: ', |
|
| 20836 | timeout : 'Your request timed out' |
|
| 20837 | }, |
|
| 20838 | ||
| 20839 | regExp : { |
|
| 20840 | required : /\{\$*[A-z0-9]+\}/g, |
|
| 20841 | optional : /\{\/\$*[A-z0-9]+\}/g, |
|
| 20842 | }, |
|
| 20843 | ||
| 20844 | className: { |
|
| 20845 | loading : 'loading', |
|
| 20846 | error : 'error' |
|
| 20847 | }, |
|
| 20848 | ||
| 20849 | selector: { |
|
| 20850 | disabled : '.disabled', |
|
| 20851 | form : 'form' |
|
| 20852 | }, |
|
| 20853 | ||
| 20854 | metadata: { |
|
| 20855 | action : 'action', |
|
| 20856 | url : 'url' |
|
| 20857 | } |
|
| 20858 | }; |
|
| 20859 | ||
| 20860 | ||
| 20861 | ||
| 20862 | })( jQuery, window, document ); |
|
| 20863 | ||
| 20864 | /*! |
|
| 20865 | * # Semantic UI 2.2.11 - State |
|
| @@ 11-1167 (lines=1157) @@ | ||
| 8 | * |
|
| 9 | */ |
|
| 10 | ||
| 11 | ;(function ($, window, document, undefined) { |
|
| 12 | ||
| 13 | "use strict"; |
|
| 14 | ||
| 15 | var |
|
| 16 | window = (typeof window != 'undefined' && window.Math == Math) |
|
| 17 | ? window |
|
| 18 | : (typeof self != 'undefined' && self.Math == Math) |
|
| 19 | ? self |
|
| 20 | : Function('return this')() |
|
| 21 | ; |
|
| 22 | ||
| 23 | $.api = $.fn.api = function(parameters) { |
|
| 24 | ||
| 25 | var |
|
| 26 | // use window context if none specified |
|
| 27 | $allModules = $.isFunction(this) |
|
| 28 | ? $(window) |
|
| 29 | : $(this), |
|
| 30 | moduleSelector = $allModules.selector || '', |
|
| 31 | time = new Date().getTime(), |
|
| 32 | performance = [], |
|
| 33 | ||
| 34 | query = arguments[0], |
|
| 35 | methodInvoked = (typeof query == 'string'), |
|
| 36 | queryArguments = [].slice.call(arguments, 1), |
|
| 37 | ||
| 38 | returnedValue |
|
| 39 | ; |
|
| 40 | ||
| 41 | $allModules |
|
| 42 | .each(function() { |
|
| 43 | var |
|
| 44 | settings = ( $.isPlainObject(parameters) ) |
|
| 45 | ? $.extend(true, {}, $.fn.api.settings, parameters) |
|
| 46 | : $.extend({}, $.fn.api.settings), |
|
| 47 | ||
| 48 | // internal aliases |
|
| 49 | namespace = settings.namespace, |
|
| 50 | metadata = settings.metadata, |
|
| 51 | selector = settings.selector, |
|
| 52 | error = settings.error, |
|
| 53 | className = settings.className, |
|
| 54 | ||
| 55 | // define namespaces for modules |
|
| 56 | eventNamespace = '.' + namespace, |
|
| 57 | moduleNamespace = 'module-' + namespace, |
|
| 58 | ||
| 59 | // element that creates request |
|
| 60 | $module = $(this), |
|
| 61 | $form = $module.closest(selector.form), |
|
| 62 | ||
| 63 | // context used for state |
|
| 64 | $context = (settings.stateContext) |
|
| 65 | ? $(settings.stateContext) |
|
| 66 | : $module, |
|
| 67 | ||
| 68 | // request details |
|
| 69 | ajaxSettings, |
|
| 70 | requestSettings, |
|
| 71 | url, |
|
| 72 | data, |
|
| 73 | requestStartTime, |
|
| 74 | ||
| 75 | // standard module |
|
| 76 | element = this, |
|
| 77 | context = $context[0], |
|
| 78 | instance = $module.data(moduleNamespace), |
|
| 79 | module |
|
| 80 | ; |
|
| 81 | ||
| 82 | module = { |
|
| 83 | ||
| 84 | initialize: function() { |
|
| 85 | if(!methodInvoked) { |
|
| 86 | module.bind.events(); |
|
| 87 | } |
|
| 88 | module.instantiate(); |
|
| 89 | }, |
|
| 90 | ||
| 91 | instantiate: function() { |
|
| 92 | module.verbose('Storing instance of module', module); |
|
| 93 | instance = module; |
|
| 94 | $module |
|
| 95 | .data(moduleNamespace, instance) |
|
| 96 | ; |
|
| 97 | }, |
|
| 98 | ||
| 99 | destroy: function() { |
|
| 100 | module.verbose('Destroying previous module for', element); |
|
| 101 | $module |
|
| 102 | .removeData(moduleNamespace) |
|
| 103 | .off(eventNamespace) |
|
| 104 | ; |
|
| 105 | }, |
|
| 106 | ||
| 107 | bind: { |
|
| 108 | events: function() { |
|
| 109 | var |
|
| 110 | triggerEvent = module.get.event() |
|
| 111 | ; |
|
| 112 | if( triggerEvent ) { |
|
| 113 | module.verbose('Attaching API events to element', triggerEvent); |
|
| 114 | $module |
|
| 115 | .on(triggerEvent + eventNamespace, module.event.trigger) |
|
| 116 | ; |
|
| 117 | } |
|
| 118 | else if(settings.on == 'now') { |
|
| 119 | module.debug('Querying API endpoint immediately'); |
|
| 120 | module.query(); |
|
| 121 | } |
|
| 122 | } |
|
| 123 | }, |
|
| 124 | ||
| 125 | decode: { |
|
| 126 | json: function(response) { |
|
| 127 | if(response !== undefined && typeof response == 'string') { |
|
| 128 | try { |
|
| 129 | response = JSON.parse(response); |
|
| 130 | } |
|
| 131 | catch(e) { |
|
| 132 | // isnt json string |
|
| 133 | } |
|
| 134 | } |
|
| 135 | return response; |
|
| 136 | } |
|
| 137 | }, |
|
| 138 | ||
| 139 | read: { |
|
| 140 | cachedResponse: function(url) { |
|
| 141 | var |
|
| 142 | response |
|
| 143 | ; |
|
| 144 | if(window.Storage === undefined) { |
|
| 145 | module.error(error.noStorage); |
|
| 146 | return; |
|
| 147 | } |
|
| 148 | response = sessionStorage.getItem(url); |
|
| 149 | module.debug('Using cached response', url, response); |
|
| 150 | response = module.decode.json(response); |
|
| 151 | return response; |
|
| 152 | } |
|
| 153 | }, |
|
| 154 | write: { |
|
| 155 | cachedResponse: function(url, response) { |
|
| 156 | if(response && response === '') { |
|
| 157 | module.debug('Response empty, not caching', response); |
|
| 158 | return; |
|
| 159 | } |
|
| 160 | if(window.Storage === undefined) { |
|
| 161 | module.error(error.noStorage); |
|
| 162 | return; |
|
| 163 | } |
|
| 164 | if( $.isPlainObject(response) ) { |
|
| 165 | response = JSON.stringify(response); |
|
| 166 | } |
|
| 167 | sessionStorage.setItem(url, response); |
|
| 168 | module.verbose('Storing cached response for url', url, response); |
|
| 169 | } |
|
| 170 | }, |
|
| 171 | ||
| 172 | query: function() { |
|
| 173 | ||
| 174 | if(module.is.disabled()) { |
|
| 175 | module.debug('Element is disabled API request aborted'); |
|
| 176 | return; |
|
| 177 | } |
|
| 178 | ||
| 179 | if(module.is.loading()) { |
|
| 180 | if(settings.interruptRequests) { |
|
| 181 | module.debug('Interrupting previous request'); |
|
| 182 | module.abort(); |
|
| 183 | } |
|
| 184 | else { |
|
| 185 | module.debug('Cancelling request, previous request is still pending'); |
|
| 186 | return; |
|
| 187 | } |
|
| 188 | } |
|
| 189 | ||
| 190 | // pass element metadata to url (value, text) |
|
| 191 | if(settings.defaultData) { |
|
| 192 | $.extend(true, settings.urlData, module.get.defaultData()); |
|
| 193 | } |
|
| 194 | ||
| 195 | // Add form content |
|
| 196 | if(settings.serializeForm) { |
|
| 197 | settings.data = module.add.formData(settings.data); |
|
| 198 | } |
|
| 199 | ||
| 200 | // call beforesend and get any settings changes |
|
| 201 | requestSettings = module.get.settings(); |
|
| 202 | ||
| 203 | // check if before send cancelled request |
|
| 204 | if(requestSettings === false) { |
|
| 205 | module.cancelled = true; |
|
| 206 | module.error(error.beforeSend); |
|
| 207 | return; |
|
| 208 | } |
|
| 209 | else { |
|
| 210 | module.cancelled = false; |
|
| 211 | } |
|
| 212 | ||
| 213 | // get url |
|
| 214 | url = module.get.templatedURL(); |
|
| 215 | ||
| 216 | if(!url && !module.is.mocked()) { |
|
| 217 | module.error(error.missingURL); |
|
| 218 | return; |
|
| 219 | } |
|
| 220 | ||
| 221 | // replace variables |
|
| 222 | url = module.add.urlData( url ); |
|
| 223 | // missing url parameters |
|
| 224 | if( !url && !module.is.mocked()) { |
|
| 225 | return; |
|
| 226 | } |
|
| 227 | ||
| 228 | requestSettings.url = settings.base + url; |
|
| 229 | ||
| 230 | // look for jQuery ajax parameters in settings |
|
| 231 | ajaxSettings = $.extend(true, {}, settings, { |
|
| 232 | type : settings.method || settings.type, |
|
| 233 | data : data, |
|
| 234 | url : settings.base + url, |
|
| 235 | beforeSend : settings.beforeXHR, |
|
| 236 | success : function() {}, |
|
| 237 | failure : function() {}, |
|
| 238 | complete : function() {} |
|
| 239 | }); |
|
| 240 | ||
| 241 | module.debug('Querying URL', ajaxSettings.url); |
|
| 242 | module.verbose('Using AJAX settings', ajaxSettings); |
|
| 243 | if(settings.cache === 'local' && module.read.cachedResponse(url)) { |
|
| 244 | module.debug('Response returned from local cache'); |
|
| 245 | module.request = module.create.request(); |
|
| 246 | module.request.resolveWith(context, [ module.read.cachedResponse(url) ]); |
|
| 247 | return; |
|
| 248 | } |
|
| 249 | ||
| 250 | if( !settings.throttle ) { |
|
| 251 | module.debug('Sending request', data, ajaxSettings.method); |
|
| 252 | module.send.request(); |
|
| 253 | } |
|
| 254 | else { |
|
| 255 | if(!settings.throttleFirstRequest && !module.timer) { |
|
| 256 | module.debug('Sending request', data, ajaxSettings.method); |
|
| 257 | module.send.request(); |
|
| 258 | module.timer = setTimeout(function(){}, settings.throttle); |
|
| 259 | } |
|
| 260 | else { |
|
| 261 | module.debug('Throttling request', settings.throttle); |
|
| 262 | clearTimeout(module.timer); |
|
| 263 | module.timer = setTimeout(function() { |
|
| 264 | if(module.timer) { |
|
| 265 | delete module.timer; |
|
| 266 | } |
|
| 267 | module.debug('Sending throttled request', data, ajaxSettings.method); |
|
| 268 | module.send.request(); |
|
| 269 | }, settings.throttle); |
|
| 270 | } |
|
| 271 | } |
|
| 272 | ||
| 273 | }, |
|
| 274 | ||
| 275 | should: { |
|
| 276 | removeError: function() { |
|
| 277 | return ( settings.hideError === true || (settings.hideError === 'auto' && !module.is.form()) ); |
|
| 278 | } |
|
| 279 | }, |
|
| 280 | ||
| 281 | is: { |
|
| 282 | disabled: function() { |
|
| 283 | return ($module.filter(selector.disabled).length > 0); |
|
| 284 | }, |
|
| 285 | expectingJSON: function() { |
|
| 286 | return settings.dataType === 'json' || settings.dataType === 'jsonp'; |
|
| 287 | }, |
|
| 288 | form: function() { |
|
| 289 | return $module.is('form') || $context.is('form'); |
|
| 290 | }, |
|
| 291 | mocked: function() { |
|
| 292 | return (settings.mockResponse || settings.mockResponseAsync || settings.response || settings.responseAsync); |
|
| 293 | }, |
|
| 294 | input: function() { |
|
| 295 | return $module.is('input'); |
|
| 296 | }, |
|
| 297 | loading: function() { |
|
| 298 | return (module.request) |
|
| 299 | ? (module.request.state() == 'pending') |
|
| 300 | : false |
|
| 301 | ; |
|
| 302 | }, |
|
| 303 | abortedRequest: function(xhr) { |
|
| 304 | if(xhr && xhr.readyState !== undefined && xhr.readyState === 0) { |
|
| 305 | module.verbose('XHR request determined to be aborted'); |
|
| 306 | return true; |
|
| 307 | } |
|
| 308 | else { |
|
| 309 | module.verbose('XHR request was not aborted'); |
|
| 310 | return false; |
|
| 311 | } |
|
| 312 | }, |
|
| 313 | validResponse: function(response) { |
|
| 314 | if( (!module.is.expectingJSON()) || !$.isFunction(settings.successTest) ) { |
|
| 315 | module.verbose('Response is not JSON, skipping validation', settings.successTest, response); |
|
| 316 | return true; |
|
| 317 | } |
|
| 318 | module.debug('Checking JSON returned success', settings.successTest, response); |
|
| 319 | if( settings.successTest(response) ) { |
|
| 320 | module.debug('Response passed success test', response); |
|
| 321 | return true; |
|
| 322 | } |
|
| 323 | else { |
|
| 324 | module.debug('Response failed success test', response); |
|
| 325 | return false; |
|
| 326 | } |
|
| 327 | } |
|
| 328 | }, |
|
| 329 | ||
| 330 | was: { |
|
| 331 | cancelled: function() { |
|
| 332 | return (module.cancelled || false); |
|
| 333 | }, |
|
| 334 | succesful: function() { |
|
| 335 | return (module.request && module.request.state() == 'resolved'); |
|
| 336 | }, |
|
| 337 | failure: function() { |
|
| 338 | return (module.request && module.request.state() == 'rejected'); |
|
| 339 | }, |
|
| 340 | complete: function() { |
|
| 341 | return (module.request && (module.request.state() == 'resolved' || module.request.state() == 'rejected') ); |
|
| 342 | } |
|
| 343 | }, |
|
| 344 | ||
| 345 | add: { |
|
| 346 | urlData: function(url, urlData) { |
|
| 347 | var |
|
| 348 | requiredVariables, |
|
| 349 | optionalVariables |
|
| 350 | ; |
|
| 351 | if(url) { |
|
| 352 | requiredVariables = url.match(settings.regExp.required); |
|
| 353 | optionalVariables = url.match(settings.regExp.optional); |
|
| 354 | urlData = urlData || settings.urlData; |
|
| 355 | if(requiredVariables) { |
|
| 356 | module.debug('Looking for required URL variables', requiredVariables); |
|
| 357 | $.each(requiredVariables, function(index, templatedString) { |
|
| 358 | var |
|
| 359 | // allow legacy {$var} style |
|
| 360 | variable = (templatedString.indexOf('$') !== -1) |
|
| 361 | ? templatedString.substr(2, templatedString.length - 3) |
|
| 362 | : templatedString.substr(1, templatedString.length - 2), |
|
| 363 | value = ($.isPlainObject(urlData) && urlData[variable] !== undefined) |
|
| 364 | ? urlData[variable] |
|
| 365 | : ($module.data(variable) !== undefined) |
|
| 366 | ? $module.data(variable) |
|
| 367 | : ($context.data(variable) !== undefined) |
|
| 368 | ? $context.data(variable) |
|
| 369 | : urlData[variable] |
|
| 370 | ; |
|
| 371 | // remove value |
|
| 372 | if(value === undefined) { |
|
| 373 | module.error(error.requiredParameter, variable, url); |
|
| 374 | url = false; |
|
| 375 | return false; |
|
| 376 | } |
|
| 377 | else { |
|
| 378 | module.verbose('Found required variable', variable, value); |
|
| 379 | value = (settings.encodeParameters) |
|
| 380 | ? module.get.urlEncodedValue(value) |
|
| 381 | : value |
|
| 382 | ; |
|
| 383 | url = url.replace(templatedString, value); |
|
| 384 | } |
|
| 385 | }); |
|
| 386 | } |
|
| 387 | if(optionalVariables) { |
|
| 388 | module.debug('Looking for optional URL variables', requiredVariables); |
|
| 389 | $.each(optionalVariables, function(index, templatedString) { |
|
| 390 | var |
|
| 391 | // allow legacy {/$var} style |
|
| 392 | variable = (templatedString.indexOf('$') !== -1) |
|
| 393 | ? templatedString.substr(3, templatedString.length - 4) |
|
| 394 | : templatedString.substr(2, templatedString.length - 3), |
|
| 395 | value = ($.isPlainObject(urlData) && urlData[variable] !== undefined) |
|
| 396 | ? urlData[variable] |
|
| 397 | : ($module.data(variable) !== undefined) |
|
| 398 | ? $module.data(variable) |
|
| 399 | : ($context.data(variable) !== undefined) |
|
| 400 | ? $context.data(variable) |
|
| 401 | : urlData[variable] |
|
| 402 | ; |
|
| 403 | // optional replacement |
|
| 404 | if(value !== undefined) { |
|
| 405 | module.verbose('Optional variable Found', variable, value); |
|
| 406 | url = url.replace(templatedString, value); |
|
| 407 | } |
|
| 408 | else { |
|
| 409 | module.verbose('Optional variable not found', variable); |
|
| 410 | // remove preceding slash if set |
|
| 411 | if(url.indexOf('/' + templatedString) !== -1) { |
|
| 412 | url = url.replace('/' + templatedString, ''); |
|
| 413 | } |
|
| 414 | else { |
|
| 415 | url = url.replace(templatedString, ''); |
|
| 416 | } |
|
| 417 | } |
|
| 418 | }); |
|
| 419 | } |
|
| 420 | } |
|
| 421 | return url; |
|
| 422 | }, |
|
| 423 | formData: function(data) { |
|
| 424 | var |
|
| 425 | canSerialize = ($.fn.serializeObject !== undefined), |
|
| 426 | formData = (canSerialize) |
|
| 427 | ? $form.serializeObject() |
|
| 428 | : $form.serialize(), |
|
| 429 | hasOtherData |
|
| 430 | ; |
|
| 431 | data = data || settings.data; |
|
| 432 | hasOtherData = $.isPlainObject(data); |
|
| 433 | ||
| 434 | if(hasOtherData) { |
|
| 435 | if(canSerialize) { |
|
| 436 | module.debug('Extending existing data with form data', data, formData); |
|
| 437 | data = $.extend(true, {}, data, formData); |
|
| 438 | } |
|
| 439 | else { |
|
| 440 | module.error(error.missingSerialize); |
|
| 441 | module.debug('Cant extend data. Replacing data with form data', data, formData); |
|
| 442 | data = formData; |
|
| 443 | } |
|
| 444 | } |
|
| 445 | else { |
|
| 446 | module.debug('Adding form data', formData); |
|
| 447 | data = formData; |
|
| 448 | } |
|
| 449 | return data; |
|
| 450 | } |
|
| 451 | }, |
|
| 452 | ||
| 453 | send: { |
|
| 454 | request: function() { |
|
| 455 | module.set.loading(); |
|
| 456 | module.request = module.create.request(); |
|
| 457 | if( module.is.mocked() ) { |
|
| 458 | module.mockedXHR = module.create.mockedXHR(); |
|
| 459 | } |
|
| 460 | else { |
|
| 461 | module.xhr = module.create.xhr(); |
|
| 462 | } |
|
| 463 | settings.onRequest.call(context, module.request, module.xhr); |
|
| 464 | } |
|
| 465 | }, |
|
| 466 | ||
| 467 | event: { |
|
| 468 | trigger: function(event) { |
|
| 469 | module.query(); |
|
| 470 | if(event.type == 'submit' || event.type == 'click') { |
|
| 471 | event.preventDefault(); |
|
| 472 | } |
|
| 473 | }, |
|
| 474 | xhr: { |
|
| 475 | always: function() { |
|
| 476 | // nothing special |
|
| 477 | }, |
|
| 478 | done: function(response, textStatus, xhr) { |
|
| 479 | var |
|
| 480 | context = this, |
|
| 481 | elapsedTime = (new Date().getTime() - requestStartTime), |
|
| 482 | timeLeft = (settings.loadingDuration - elapsedTime), |
|
| 483 | translatedResponse = ( $.isFunction(settings.onResponse) ) |
|
| 484 | ? module.is.expectingJSON() |
|
| 485 | ? settings.onResponse.call(context, $.extend(true, {}, response)) |
|
| 486 | : settings.onResponse.call(context, response) |
|
| 487 | : false |
|
| 488 | ; |
|
| 489 | timeLeft = (timeLeft > 0) |
|
| 490 | ? timeLeft |
|
| 491 | : 0 |
|
| 492 | ; |
|
| 493 | if(translatedResponse) { |
|
| 494 | module.debug('Modified API response in onResponse callback', settings.onResponse, translatedResponse, response); |
|
| 495 | response = translatedResponse; |
|
| 496 | } |
|
| 497 | if(timeLeft > 0) { |
|
| 498 | module.debug('Response completed early delaying state change by', timeLeft); |
|
| 499 | } |
|
| 500 | setTimeout(function() { |
|
| 501 | if( module.is.validResponse(response) ) { |
|
| 502 | module.request.resolveWith(context, [response, xhr]); |
|
| 503 | } |
|
| 504 | else { |
|
| 505 | module.request.rejectWith(context, [xhr, 'invalid']); |
|
| 506 | } |
|
| 507 | }, timeLeft); |
|
| 508 | }, |
|
| 509 | fail: function(xhr, status, httpMessage) { |
|
| 510 | var |
|
| 511 | context = this, |
|
| 512 | elapsedTime = (new Date().getTime() - requestStartTime), |
|
| 513 | timeLeft = (settings.loadingDuration - elapsedTime) |
|
| 514 | ; |
|
| 515 | timeLeft = (timeLeft > 0) |
|
| 516 | ? timeLeft |
|
| 517 | : 0 |
|
| 518 | ; |
|
| 519 | if(timeLeft > 0) { |
|
| 520 | module.debug('Response completed early delaying state change by', timeLeft); |
|
| 521 | } |
|
| 522 | setTimeout(function() { |
|
| 523 | if( module.is.abortedRequest(xhr) ) { |
|
| 524 | module.request.rejectWith(context, [xhr, 'aborted', httpMessage]); |
|
| 525 | } |
|
| 526 | else { |
|
| 527 | module.request.rejectWith(context, [xhr, 'error', status, httpMessage]); |
|
| 528 | } |
|
| 529 | }, timeLeft); |
|
| 530 | } |
|
| 531 | }, |
|
| 532 | request: { |
|
| 533 | done: function(response, xhr) { |
|
| 534 | module.debug('Successful API Response', response); |
|
| 535 | if(settings.cache === 'local' && url) { |
|
| 536 | module.write.cachedResponse(url, response); |
|
| 537 | module.debug('Saving server response locally', module.cache); |
|
| 538 | } |
|
| 539 | settings.onSuccess.call(context, response, $module, xhr); |
|
| 540 | }, |
|
| 541 | complete: function(firstParameter, secondParameter) { |
|
| 542 | var |
|
| 543 | xhr, |
|
| 544 | response |
|
| 545 | ; |
|
| 546 | // have to guess callback parameters based on request success |
|
| 547 | if( module.was.succesful() ) { |
|
| 548 | response = firstParameter; |
|
| 549 | xhr = secondParameter; |
|
| 550 | } |
|
| 551 | else { |
|
| 552 | xhr = firstParameter; |
|
| 553 | response = module.get.responseFromXHR(xhr); |
|
| 554 | } |
|
| 555 | module.remove.loading(); |
|
| 556 | settings.onComplete.call(context, response, $module, xhr); |
|
| 557 | }, |
|
| 558 | fail: function(xhr, status, httpMessage) { |
|
| 559 | var |
|
| 560 | // pull response from xhr if available |
|
| 561 | response = module.get.responseFromXHR(xhr), |
|
| 562 | errorMessage = module.get.errorFromRequest(response, status, httpMessage) |
|
| 563 | ; |
|
| 564 | if(status == 'aborted') { |
|
| 565 | module.debug('XHR Aborted (Most likely caused by page navigation or CORS Policy)', status, httpMessage); |
|
| 566 | settings.onAbort.call(context, status, $module, xhr); |
|
| 567 | return true; |
|
| 568 | } |
|
| 569 | else if(status == 'invalid') { |
|
| 570 | module.debug('JSON did not pass success test. A server-side error has most likely occurred', response); |
|
| 571 | } |
|
| 572 | else if(status == 'error') { |
|
| 573 | if(xhr !== undefined) { |
|
| 574 | module.debug('XHR produced a server error', status, httpMessage); |
|
| 575 | // make sure we have an error to display to console |
|
| 576 | if( xhr.status != 200 && httpMessage !== undefined && httpMessage !== '') { |
|
| 577 | module.error(error.statusMessage + httpMessage, ajaxSettings.url); |
|
| 578 | } |
|
| 579 | settings.onError.call(context, errorMessage, $module, xhr); |
|
| 580 | } |
|
| 581 | } |
|
| 582 | ||
| 583 | if(settings.errorDuration && status !== 'aborted') { |
|
| 584 | module.debug('Adding error state'); |
|
| 585 | module.set.error(); |
|
| 586 | if( module.should.removeError() ) { |
|
| 587 | setTimeout(module.remove.error, settings.errorDuration); |
|
| 588 | } |
|
| 589 | } |
|
| 590 | module.debug('API Request failed', errorMessage, xhr); |
|
| 591 | settings.onFailure.call(context, response, $module, xhr); |
|
| 592 | } |
|
| 593 | } |
|
| 594 | }, |
|
| 595 | ||
| 596 | create: { |
|
| 597 | ||
| 598 | request: function() { |
|
| 599 | // api request promise |
|
| 600 | return $.Deferred() |
|
| 601 | .always(module.event.request.complete) |
|
| 602 | .done(module.event.request.done) |
|
| 603 | .fail(module.event.request.fail) |
|
| 604 | ; |
|
| 605 | }, |
|
| 606 | ||
| 607 | mockedXHR: function () { |
|
| 608 | var |
|
| 609 | // xhr does not simulate these properties of xhr but must return them |
|
| 610 | textStatus = false, |
|
| 611 | status = false, |
|
| 612 | httpMessage = false, |
|
| 613 | responder = settings.mockResponse || settings.response, |
|
| 614 | asyncResponder = settings.mockResponseAsync || settings.responseAsync, |
|
| 615 | asyncCallback, |
|
| 616 | response, |
|
| 617 | mockedXHR |
|
| 618 | ; |
|
| 619 | ||
| 620 | mockedXHR = $.Deferred() |
|
| 621 | .always(module.event.xhr.complete) |
|
| 622 | .done(module.event.xhr.done) |
|
| 623 | .fail(module.event.xhr.fail) |
|
| 624 | ; |
|
| 625 | ||
| 626 | if(responder) { |
|
| 627 | if( $.isFunction(responder) ) { |
|
| 628 | module.debug('Using specified synchronous callback', responder); |
|
| 629 | response = responder.call(context, requestSettings); |
|
| 630 | } |
|
| 631 | else { |
|
| 632 | module.debug('Using settings specified response', responder); |
|
| 633 | response = responder; |
|
| 634 | } |
|
| 635 | // simulating response |
|
| 636 | mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); |
|
| 637 | } |
|
| 638 | else if( $.isFunction(asyncResponder) ) { |
|
| 639 | asyncCallback = function(response) { |
|
| 640 | module.debug('Async callback returned response', response); |
|
| 641 | ||
| 642 | if(response) { |
|
| 643 | mockedXHR.resolveWith(context, [ response, textStatus, { responseText: response }]); |
|
| 644 | } |
|
| 645 | else { |
|
| 646 | mockedXHR.rejectWith(context, [{ responseText: response }, status, httpMessage]); |
|
| 647 | } |
|
| 648 | }; |
|
| 649 | module.debug('Using specified async response callback', asyncResponder); |
|
| 650 | asyncResponder.call(context, requestSettings, asyncCallback); |
|
| 651 | } |
|
| 652 | return mockedXHR; |
|
| 653 | }, |
|
| 654 | ||
| 655 | xhr: function() { |
|
| 656 | var |
|
| 657 | xhr |
|
| 658 | ; |
|
| 659 | // ajax request promise |
|
| 660 | xhr = $.ajax(ajaxSettings) |
|
| 661 | .always(module.event.xhr.always) |
|
| 662 | .done(module.event.xhr.done) |
|
| 663 | .fail(module.event.xhr.fail) |
|
| 664 | ; |
|
| 665 | module.verbose('Created server request', xhr, ajaxSettings); |
|
| 666 | return xhr; |
|
| 667 | } |
|
| 668 | }, |
|
| 669 | ||
| 670 | set: { |
|
| 671 | error: function() { |
|
| 672 | module.verbose('Adding error state to element', $context); |
|
| 673 | $context.addClass(className.error); |
|
| 674 | }, |
|
| 675 | loading: function() { |
|
| 676 | module.verbose('Adding loading state to element', $context); |
|
| 677 | $context.addClass(className.loading); |
|
| 678 | requestStartTime = new Date().getTime(); |
|
| 679 | } |
|
| 680 | }, |
|
| 681 | ||
| 682 | remove: { |
|
| 683 | error: function() { |
|
| 684 | module.verbose('Removing error state from element', $context); |
|
| 685 | $context.removeClass(className.error); |
|
| 686 | }, |
|
| 687 | loading: function() { |
|
| 688 | module.verbose('Removing loading state from element', $context); |
|
| 689 | $context.removeClass(className.loading); |
|
| 690 | } |
|
| 691 | }, |
|
| 692 | ||
| 693 | get: { |
|
| 694 | responseFromXHR: function(xhr) { |
|
| 695 | return $.isPlainObject(xhr) |
|
| 696 | ? (module.is.expectingJSON()) |
|
| 697 | ? module.decode.json(xhr.responseText) |
|
| 698 | : xhr.responseText |
|
| 699 | : false |
|
| 700 | ; |
|
| 701 | }, |
|
| 702 | errorFromRequest: function(response, status, httpMessage) { |
|
| 703 | return ($.isPlainObject(response) && response.error !== undefined) |
|
| 704 | ? response.error // use json error message |
|
| 705 | : (settings.error[status] !== undefined) // use server error message |
|
| 706 | ? settings.error[status] |
|
| 707 | : httpMessage |
|
| 708 | ; |
|
| 709 | }, |
|
| 710 | request: function() { |
|
| 711 | return module.request || false; |
|
| 712 | }, |
|
| 713 | xhr: function() { |
|
| 714 | return module.xhr || false; |
|
| 715 | }, |
|
| 716 | settings: function() { |
|
| 717 | var |
|
| 718 | runSettings |
|
| 719 | ; |
|
| 720 | runSettings = settings.beforeSend.call(context, settings); |
|
| 721 | if(runSettings) { |
|
| 722 | if(runSettings.success !== undefined) { |
|
| 723 | module.debug('Legacy success callback detected', runSettings); |
|
| 724 | module.error(error.legacyParameters, runSettings.success); |
|
| 725 | runSettings.onSuccess = runSettings.success; |
|
| 726 | } |
|
| 727 | if(runSettings.failure !== undefined) { |
|
| 728 | module.debug('Legacy failure callback detected', runSettings); |
|
| 729 | module.error(error.legacyParameters, runSettings.failure); |
|
| 730 | runSettings.onFailure = runSettings.failure; |
|
| 731 | } |
|
| 732 | if(runSettings.complete !== undefined) { |
|
| 733 | module.debug('Legacy complete callback detected', runSettings); |
|
| 734 | module.error(error.legacyParameters, runSettings.complete); |
|
| 735 | runSettings.onComplete = runSettings.complete; |
|
| 736 | } |
|
| 737 | } |
|
| 738 | if(runSettings === undefined) { |
|
| 739 | module.error(error.noReturnedValue); |
|
| 740 | } |
|
| 741 | if(runSettings === false) { |
|
| 742 | return runSettings; |
|
| 743 | } |
|
| 744 | return (runSettings !== undefined) |
|
| 745 | ? $.extend(true, {}, runSettings) |
|
| 746 | : $.extend(true, {}, settings) |
|
| 747 | ; |
|
| 748 | }, |
|
| 749 | urlEncodedValue: function(value) { |
|
| 750 | var |
|
| 751 | decodedValue = window.decodeURIComponent(value), |
|
| 752 | encodedValue = window.encodeURIComponent(value), |
|
| 753 | alreadyEncoded = (decodedValue !== value) |
|
| 754 | ; |
|
| 755 | if(alreadyEncoded) { |
|
| 756 | module.debug('URL value is already encoded, avoiding double encoding', value); |
|
| 757 | return value; |
|
| 758 | } |
|
| 759 | module.verbose('Encoding value using encodeURIComponent', value, encodedValue); |
|
| 760 | return encodedValue; |
|
| 761 | }, |
|
| 762 | defaultData: function() { |
|
| 763 | var |
|
| 764 | data = {} |
|
| 765 | ; |
|
| 766 | if( !$.isWindow(element) ) { |
|
| 767 | if( module.is.input() ) { |
|
| 768 | data.value = $module.val(); |
|
| 769 | } |
|
| 770 | else if( module.is.form() ) { |
|
| 771 | ||
| 772 | } |
|
| 773 | else { |
|
| 774 | data.text = $module.text(); |
|
| 775 | } |
|
| 776 | } |
|
| 777 | return data; |
|
| 778 | }, |
|
| 779 | event: function() { |
|
| 780 | if( $.isWindow(element) || settings.on == 'now' ) { |
|
| 781 | module.debug('API called without element, no events attached'); |
|
| 782 | return false; |
|
| 783 | } |
|
| 784 | else if(settings.on == 'auto') { |
|
| 785 | if( $module.is('input') ) { |
|
| 786 | return (element.oninput !== undefined) |
|
| 787 | ? 'input' |
|
| 788 | : (element.onpropertychange !== undefined) |
|
| 789 | ? 'propertychange' |
|
| 790 | : 'keyup' |
|
| 791 | ; |
|
| 792 | } |
|
| 793 | else if( $module.is('form') ) { |
|
| 794 | return 'submit'; |
|
| 795 | } |
|
| 796 | else { |
|
| 797 | return 'click'; |
|
| 798 | } |
|
| 799 | } |
|
| 800 | else { |
|
| 801 | return settings.on; |
|
| 802 | } |
|
| 803 | }, |
|
| 804 | templatedURL: function(action) { |
|
| 805 | action = action || $module.data(metadata.action) || settings.action || false; |
|
| 806 | url = $module.data(metadata.url) || settings.url || false; |
|
| 807 | if(url) { |
|
| 808 | module.debug('Using specified url', url); |
|
| 809 | return url; |
|
| 810 | } |
|
| 811 | if(action) { |
|
| 812 | module.debug('Looking up url for action', action, settings.api); |
|
| 813 | if(settings.api[action] === undefined && !module.is.mocked()) { |
|
| 814 | module.error(error.missingAction, settings.action, settings.api); |
|
| 815 | return; |
|
| 816 | } |
|
| 817 | url = settings.api[action]; |
|
| 818 | } |
|
| 819 | else if( module.is.form() ) { |
|
| 820 | url = $module.attr('action') || $context.attr('action') || false; |
|
| 821 | module.debug('No url or action specified, defaulting to form action', url); |
|
| 822 | } |
|
| 823 | return url; |
|
| 824 | } |
|
| 825 | }, |
|
| 826 | ||
| 827 | abort: function() { |
|
| 828 | var |
|
| 829 | xhr = module.get.xhr() |
|
| 830 | ; |
|
| 831 | if( xhr && xhr.state() !== 'resolved') { |
|
| 832 | module.debug('Cancelling API request'); |
|
| 833 | xhr.abort(); |
|
| 834 | } |
|
| 835 | }, |
|
| 836 | ||
| 837 | // reset state |
|
| 838 | reset: function() { |
|
| 839 | module.remove.error(); |
|
| 840 | module.remove.loading(); |
|
| 841 | }, |
|
| 842 | ||
| 843 | setting: function(name, value) { |
|
| 844 | module.debug('Changing setting', name, value); |
|
| 845 | if( $.isPlainObject(name) ) { |
|
| 846 | $.extend(true, settings, name); |
|
| 847 | } |
|
| 848 | else if(value !== undefined) { |
|
| 849 | if($.isPlainObject(settings[name])) { |
|
| 850 | $.extend(true, settings[name], value); |
|
| 851 | } |
|
| 852 | else { |
|
| 853 | settings[name] = value; |
|
| 854 | } |
|
| 855 | } |
|
| 856 | else { |
|
| 857 | return settings[name]; |
|
| 858 | } |
|
| 859 | }, |
|
| 860 | internal: function(name, value) { |
|
| 861 | if( $.isPlainObject(name) ) { |
|
| 862 | $.extend(true, module, name); |
|
| 863 | } |
|
| 864 | else if(value !== undefined) { |
|
| 865 | module[name] = value; |
|
| 866 | } |
|
| 867 | else { |
|
| 868 | return module[name]; |
|
| 869 | } |
|
| 870 | }, |
|
| 871 | debug: function() { |
|
| 872 | if(!settings.silent && settings.debug) { |
|
| 873 | if(settings.performance) { |
|
| 874 | module.performance.log(arguments); |
|
| 875 | } |
|
| 876 | else { |
|
| 877 | module.debug = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 878 | module.debug.apply(console, arguments); |
|
| 879 | } |
|
| 880 | } |
|
| 881 | }, |
|
| 882 | verbose: function() { |
|
| 883 | if(!settings.silent && settings.verbose && settings.debug) { |
|
| 884 | if(settings.performance) { |
|
| 885 | module.performance.log(arguments); |
|
| 886 | } |
|
| 887 | else { |
|
| 888 | module.verbose = Function.prototype.bind.call(console.info, console, settings.name + ':'); |
|
| 889 | module.verbose.apply(console, arguments); |
|
| 890 | } |
|
| 891 | } |
|
| 892 | }, |
|
| 893 | error: function() { |
|
| 894 | if(!settings.silent) { |
|
| 895 | module.error = Function.prototype.bind.call(console.error, console, settings.name + ':'); |
|
| 896 | module.error.apply(console, arguments); |
|
| 897 | } |
|
| 898 | }, |
|
| 899 | performance: { |
|
| 900 | log: function(message) { |
|
| 901 | var |
|
| 902 | currentTime, |
|
| 903 | executionTime, |
|
| 904 | previousTime |
|
| 905 | ; |
|
| 906 | if(settings.performance) { |
|
| 907 | currentTime = new Date().getTime(); |
|
| 908 | previousTime = time || currentTime; |
|
| 909 | executionTime = currentTime - previousTime; |
|
| 910 | time = currentTime; |
|
| 911 | performance.push({ |
|
| 912 | 'Name' : message[0], |
|
| 913 | 'Arguments' : [].slice.call(message, 1) || '', |
|
| 914 | //'Element' : element, |
|
| 915 | 'Execution Time' : executionTime |
|
| 916 | }); |
|
| 917 | } |
|
| 918 | clearTimeout(module.performance.timer); |
|
| 919 | module.performance.timer = setTimeout(module.performance.display, 500); |
|
| 920 | }, |
|
| 921 | display: function() { |
|
| 922 | var |
|
| 923 | title = settings.name + ':', |
|
| 924 | totalTime = 0 |
|
| 925 | ; |
|
| 926 | time = false; |
|
| 927 | clearTimeout(module.performance.timer); |
|
| 928 | $.each(performance, function(index, data) { |
|
| 929 | totalTime += data['Execution Time']; |
|
| 930 | }); |
|
| 931 | title += ' ' + totalTime + 'ms'; |
|
| 932 | if(moduleSelector) { |
|
| 933 | title += ' \'' + moduleSelector + '\''; |
|
| 934 | } |
|
| 935 | if( (console.group !== undefined || console.table !== undefined) && performance.length > 0) { |
|
| 936 | console.groupCollapsed(title); |
|
| 937 | if(console.table) { |
|
| 938 | console.table(performance); |
|
| 939 | } |
|
| 940 | else { |
|
| 941 | $.each(performance, function(index, data) { |
|
| 942 | console.log(data['Name'] + ': ' + data['Execution Time']+'ms'); |
|
| 943 | }); |
|
| 944 | } |
|
| 945 | console.groupEnd(); |
|
| 946 | } |
|
| 947 | performance = []; |
|
| 948 | } |
|
| 949 | }, |
|
| 950 | invoke: function(query, passedArguments, context) { |
|
| 951 | var |
|
| 952 | object = instance, |
|
| 953 | maxDepth, |
|
| 954 | found, |
|
| 955 | response |
|
| 956 | ; |
|
| 957 | passedArguments = passedArguments || queryArguments; |
|
| 958 | context = element || context; |
|
| 959 | if(typeof query == 'string' && object !== undefined) { |
|
| 960 | query = query.split(/[\. ]/); |
|
| 961 | maxDepth = query.length - 1; |
|
| 962 | $.each(query, function(depth, value) { |
|
| 963 | var camelCaseValue = (depth != maxDepth) |
|
| 964 | ? value + query[depth + 1].charAt(0).toUpperCase() + query[depth + 1].slice(1) |
|
| 965 | : query |
|
| 966 | ; |
|
| 967 | if( $.isPlainObject( object[camelCaseValue] ) && (depth != maxDepth) ) { |
|
| 968 | object = object[camelCaseValue]; |
|
| 969 | } |
|
| 970 | else if( object[camelCaseValue] !== undefined ) { |
|
| 971 | found = object[camelCaseValue]; |
|
| 972 | return false; |
|
| 973 | } |
|
| 974 | else if( $.isPlainObject( object[value] ) && (depth != maxDepth) ) { |
|
| 975 | object = object[value]; |
|
| 976 | } |
|
| 977 | else if( object[value] !== undefined ) { |
|
| 978 | found = object[value]; |
|
| 979 | return false; |
|
| 980 | } |
|
| 981 | else { |
|
| 982 | module.error(error.method, query); |
|
| 983 | return false; |
|
| 984 | } |
|
| 985 | }); |
|
| 986 | } |
|
| 987 | if ( $.isFunction( found ) ) { |
|
| 988 | response = found.apply(context, passedArguments); |
|
| 989 | } |
|
| 990 | else if(found !== undefined) { |
|
| 991 | response = found; |
|
| 992 | } |
|
| 993 | if($.isArray(returnedValue)) { |
|
| 994 | returnedValue.push(response); |
|
| 995 | } |
|
| 996 | else if(returnedValue !== undefined) { |
|
| 997 | returnedValue = [returnedValue, response]; |
|
| 998 | } |
|
| 999 | else if(response !== undefined) { |
|
| 1000 | returnedValue = response; |
|
| 1001 | } |
|
| 1002 | return found; |
|
| 1003 | } |
|
| 1004 | }; |
|
| 1005 | ||
| 1006 | if(methodInvoked) { |
|
| 1007 | if(instance === undefined) { |
|
| 1008 | module.initialize(); |
|
| 1009 | } |
|
| 1010 | module.invoke(query); |
|
| 1011 | } |
|
| 1012 | else { |
|
| 1013 | if(instance !== undefined) { |
|
| 1014 | instance.invoke('destroy'); |
|
| 1015 | } |
|
| 1016 | module.initialize(); |
|
| 1017 | } |
|
| 1018 | }) |
|
| 1019 | ; |
|
| 1020 | ||
| 1021 | return (returnedValue !== undefined) |
|
| 1022 | ? returnedValue |
|
| 1023 | : this |
|
| 1024 | ; |
|
| 1025 | }; |
|
| 1026 | ||
| 1027 | $.api.settings = { |
|
| 1028 | ||
| 1029 | name : 'API', |
|
| 1030 | namespace : 'api', |
|
| 1031 | ||
| 1032 | debug : false, |
|
| 1033 | verbose : false, |
|
| 1034 | performance : true, |
|
| 1035 | ||
| 1036 | // object containing all templates endpoints |
|
| 1037 | api : {}, |
|
| 1038 | ||
| 1039 | // whether to cache responses |
|
| 1040 | cache : true, |
|
| 1041 | ||
| 1042 | // whether new requests should abort previous requests |
|
| 1043 | interruptRequests : true, |
|
| 1044 | ||
| 1045 | // event binding |
|
| 1046 | on : 'auto', |
|
| 1047 | ||
| 1048 | // context for applying state classes |
|
| 1049 | stateContext : false, |
|
| 1050 | ||
| 1051 | // duration for loading state |
|
| 1052 | loadingDuration : 0, |
|
| 1053 | ||
| 1054 | // whether to hide errors after a period of time |
|
| 1055 | hideError : 'auto', |
|
| 1056 | ||
| 1057 | // duration for error state |
|
| 1058 | errorDuration : 2000, |
|
| 1059 | ||
| 1060 | // whether parameters should be encoded with encodeURIComponent |
|
| 1061 | encodeParameters : true, |
|
| 1062 | ||
| 1063 | // API action to use |
|
| 1064 | action : false, |
|
| 1065 | ||
| 1066 | // templated URL to use |
|
| 1067 | url : false, |
|
| 1068 | ||
| 1069 | // base URL to apply to all endpoints |
|
| 1070 | base : '', |
|
| 1071 | ||
| 1072 | // data that will |
|
| 1073 | urlData : {}, |
|
| 1074 | ||
| 1075 | // whether to add default data to url data |
|
| 1076 | defaultData : true, |
|
| 1077 | ||
| 1078 | // whether to serialize closest form |
|
| 1079 | serializeForm : false, |
|
| 1080 | ||
| 1081 | // how long to wait before request should occur |
|
| 1082 | throttle : 0, |
|
| 1083 | ||
| 1084 | // whether to throttle first request or only repeated |
|
| 1085 | throttleFirstRequest : true, |
|
| 1086 | ||
| 1087 | // standard ajax settings |
|
| 1088 | method : 'get', |
|
| 1089 | data : {}, |
|
| 1090 | dataType : 'json', |
|
| 1091 | ||
| 1092 | // mock response |
|
| 1093 | mockResponse : false, |
|
| 1094 | mockResponseAsync : false, |
|
| 1095 | ||
| 1096 | // aliases for mock |
|
| 1097 | response : false, |
|
| 1098 | responseAsync : false, |
|
| 1099 | ||
| 1100 | // callbacks before request |
|
| 1101 | beforeSend : function(settings) { return settings; }, |
|
| 1102 | beforeXHR : function(xhr) {}, |
|
| 1103 | onRequest : function(promise, xhr) {}, |
|
| 1104 | ||
| 1105 | // after request |
|
| 1106 | onResponse : false, // function(response) { }, |
|
| 1107 | ||
| 1108 | // response was successful, if JSON passed validation |
|
| 1109 | onSuccess : function(response, $module) {}, |
|
| 1110 | ||
| 1111 | // request finished without aborting |
|
| 1112 | onComplete : function(response, $module) {}, |
|
| 1113 | ||
| 1114 | // failed JSON success test |
|
| 1115 | onFailure : function(response, $module) {}, |
|
| 1116 | ||
| 1117 | // server error |
|
| 1118 | onError : function(errorMessage, $module) {}, |
|
| 1119 | ||
| 1120 | // request aborted |
|
| 1121 | onAbort : function(errorMessage, $module) {}, |
|
| 1122 | ||
| 1123 | successTest : false, |
|
| 1124 | ||
| 1125 | // errors |
|
| 1126 | error : { |
|
| 1127 | beforeSend : 'The before send function has aborted the request', |
|
| 1128 | error : 'There was an error with your request', |
|
| 1129 | exitConditions : 'API Request Aborted. Exit conditions met', |
|
| 1130 | JSONParse : 'JSON could not be parsed during error handling', |
|
| 1131 | legacyParameters : 'You are using legacy API success callback names', |
|
| 1132 | method : 'The method you called is not defined', |
|
| 1133 | missingAction : 'API action used but no url was defined', |
|
| 1134 | missingSerialize : 'jquery-serialize-object is required to add form data to an existing data object', |
|
| 1135 | missingURL : 'No URL specified for api event', |
|
| 1136 | noReturnedValue : 'The beforeSend callback must return a settings object, beforeSend ignored.', |
|
| 1137 | noStorage : 'Caching responses locally requires session storage', |
|
| 1138 | parseError : 'There was an error parsing your request', |
|
| 1139 | requiredParameter : 'Missing a required URL parameter: ', |
|
| 1140 | statusMessage : 'Server gave an error: ', |
|
| 1141 | timeout : 'Your request timed out' |
|
| 1142 | }, |
|
| 1143 | ||
| 1144 | regExp : { |
|
| 1145 | required : /\{\$*[A-z0-9]+\}/g, |
|
| 1146 | optional : /\{\/\$*[A-z0-9]+\}/g, |
|
| 1147 | }, |
|
| 1148 | ||
| 1149 | className: { |
|
| 1150 | loading : 'loading', |
|
| 1151 | error : 'error' |
|
| 1152 | }, |
|
| 1153 | ||
| 1154 | selector: { |
|
| 1155 | disabled : '.disabled', |
|
| 1156 | form : 'form' |
|
| 1157 | }, |
|
| 1158 | ||
| 1159 | metadata: { |
|
| 1160 | action : 'action', |
|
| 1161 | url : 'url' |
|
| 1162 | } |
|
| 1163 | }; |
|
| 1164 | ||
| 1165 | ||
| 1166 | ||
| 1167 | })( jQuery, window, document ); |
|
| 1168 | ||