├── .gitignore
├── LICENSE.md
├── README.md
├── example
├── index.htm
└── vendor
│ └── angular-1.2.16.min.js
└── lib
└── httpi.js
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # I am using CodeKit 2 to perform build minification.
3 |
4 | *codekit*
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 |
2 | # The MIT License (MIT)
3 |
4 | Copyright (c) 2013 [Ben Nadel][1]
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of
7 | this software and associated documentation files (the "Software"), to deal in
8 | the Software without restriction, including without limitation the rights to
9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software is furnished to do so,
11 | subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | [1]: http://www.bennadel.com
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # httpi - Lightweight AngularJS $http Wrapper For URL Interpolation
3 |
4 | by [Ben Nadel][1] (on [Google+][2])
5 |
6 | Out of the box, AngularJS provides the $http service for making AJAX (Asynchronous JavaScript and XML)
7 | requests. This is a low-level, flexible abstraction for the underlying XMLHttpRequest object. You can
8 | also include the optional $resource module, which provides a complex, persistence-oriented wrapper for
9 | the $http service. I don't particularly like the $resource module; but, it does have some features
10 | that I enjoy. I wanted to see if I could try to bridge the gap between the core $http service and the
11 | aspects of $resource that I would like to use (less all the cruft).
12 |
13 | When I look at the way I use $resource, the two features I enjoy the most are:
14 |
15 | * URL interpolation.
16 | * Encapsulation of the URL across multiple HTTP methods.
17 |
18 | I built "httpi" to add an "interpolation" (hence the "i") preprocessor before the underlying $http
19 | call was made. The preprocessor will attempt to pull values out of the params and data collection and
20 | merge them into the URL:
21 |
22 | ```js
23 | // URL is interpolated to be, /api/friends/4
24 | var promise = httpi({
25 | method: "get",
26 | url: "/api/friends/:id",
27 | params: {
28 | id: 4
29 | }
30 | });
31 | ```
32 |
33 | Note that the configuration object being passed to the httpi() service is being passed-through to the
34 | $http service.
35 |
36 | To offer an encapsulated URL across requests, I added a super lightweight recourse factory that
37 | provides VERB-oriented methods that proxy the $http service:
38 |
39 | ```js
40 | var resource = httpi.resource( "api/friends/:id" );
41 |
42 | // URL and method are automatically injected.
43 | var promise = resource.get({
44 | params: {
45 | id: 4
46 | }
47 | });
48 |
49 | // URL and method are automatically injected.
50 | var promise = resource.post({
51 | data: {
52 | id: 4,
53 | name: "Tricia",
54 | status: "Best Friend"
55 | }
56 | });
57 |
58 | // URL, method, and JSON_CALLBACK handle are automatically injected.
59 | var promise = resource.jsonp({
60 | params: {
61 | id: 4
62 | }
63 | });
64 | ```
65 |
66 | Both the httpi and the resource methods are nothing more than lightweight preprocessors - you pass-in
67 | the configuration object, it gets "massaged", and then it is passed into the $http service. This
68 | provides the flexibility of the $http service with only the best parts (in my opinion) of the optional
69 | $resource module.
70 |
71 | _**Note**: This is clearly based on my own usage patterns; your mileage may vary._
72 |
73 | ## Aborting Requests
74 |
75 | As of __AngularJS 1.2__ (or 1.1.5 unstable), you can now pass in a promise in the "timeout" property.
76 | If the promise is resolved, AngularJS will abort the underlying AJAX request. httpi will attempt to
77 | inject a .abort() in the request object if the .timeout property is not already in use:
78 |
79 | ```js
80 | // Initiate an AJAX request.
81 | var promise = httpi({
82 | method: "get",
83 | url: "/api/friends/:id",
84 | params: {
85 | id: 4
86 | }
87 | });
88 |
89 | // Abort the request.
90 | promise.abort();
91 | ```
92 |
93 | If the .timeout property was already in use, the .abort() method still exists, but it's a no-op method.
94 |
95 | ## Keeping Trailing Slashes In Interpolated URLs
96 |
97 | By default, the trailing slash will be stripped out of the interpolated URL. However, some APIs require
98 | resource requests to contian the trailing slash. If this is the case, you can add a `keepTrailingSlash`
99 | parameter to the httpi() configuration:
100 |
101 | ```js
102 | // URL is interpolated to be, /api/friends/4/
103 | var promise = httpi({
104 | method: "get",
105 | url: "/api/friends/:id/",
106 | params: {
107 | id: 4
108 | },
109 | keepTrailingSlash: true
110 | });
111 | ```
112 |
113 | You can also use this feature when using the HttpiResource module. However, in order to remove the need
114 | to pass this setting through with every resource request, you can turn it on at the resource level:
115 |
116 | ```js
117 | var resource = httpi
118 | .resource( "api/friends/:id/" )
119 | .setKeepTrailingSlash( true )
120 | ;
121 | ```
122 |
123 | Once this setting is enabled, all HTTP requests made from the given resource will allow the trailing
124 | slashes to remain in-tact, if they exist.
125 |
126 |
127 | [1]: http://www.bennadel.com
128 | [2]: https://plus.google.com/108976367067760160494?rel=author
--------------------------------------------------------------------------------
/example/index.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Using The httpi Service To Make AJAX Requests In AngularJS
8 |
9 |
10 |
11 |
12 |
13 |
14 | Using The httpi Service To Make AJAX Requests In AngularJS
15 |
16 |
17 |
18 | View the browser console - where all the action is taking place.
19 |
20 |
21 |
22 |
23 |
24 |
25 |
174 |
175 |
176 |
--------------------------------------------------------------------------------
/lib/httpi.js:
--------------------------------------------------------------------------------
1 | ;(function( ng ) {
2 |
3 | "use strict";
4 |
5 | // Define our AngularJS module.
6 | var module = ng.module( "httpi", [] );
7 |
8 |
9 | // I provide a light-weight proxy for the $http service that will interpolate the
10 | // URL using the configuration-based params and data collections.
11 | module.factory(
12 | "httpi",
13 | [ "$http", "$q", "HttpiResource",
14 | function httpiFactory( $http, $q, HttpiResource ) {
15 |
16 | // I proxy the $http service and merge the params and data values into
17 | // the URL before creating the underlying request.
18 | function httpProxy( config ) {
19 |
20 | config.url = interpolateUrl(
21 | config.url,
22 | config.params,
23 | config.data,
24 | ( config.keepTrailingSlash != true )
25 | );
26 |
27 | // NOTE: Adding the abort is a two-phase process (see below).
28 | var abort = addAbortHook( config );
29 |
30 | var request = $http( config );
31 |
32 | // Now that we have the request, inject the abort hook method. Unfortunately,
33 | // this has to be done in a two-step process since the timer has to be set up
34 | // before the request is initiated.
35 | // --
36 | // NOTE: The abort() method can be detached from the request and it will still
37 | // work properly (ie, does not rely on "this").
38 | request.abort = abort;
39 |
40 | return( request );
41 |
42 | }
43 |
44 |
45 | // I create a new Httpi Resource for the given URL.
46 | httpProxy.resource = function( url ) {
47 |
48 | return( new HttpiResource( httpProxy, url ) );
49 |
50 | };
51 |
52 |
53 | // Return the factory value.
54 | return( httpProxy );
55 |
56 |
57 | // ---
58 | // PRIVATE METHODS.
59 | // ---
60 |
61 |
62 | // If the timeout configuration is available (ie, not already set by the
63 | // user), then I inject a deferred value and return a function that will
64 | // resolve the deferred value, thereby aborting the request.
65 | // --
66 | // NOTE: This behavior is only as of AngularJS 1.1.5 (unstable) or
67 | // AngularJS 1.2 (stable).
68 | function addAbortHook( config ) {
69 |
70 | // If the timeout property is already set by the user, there's nothing we
71 | // can do - return the no-op abort method.
72 | if ( config.timeout ) {
73 |
74 | return( noopAbort );
75 |
76 | }
77 |
78 | // If the timeout wasn't already set, we can create an abort that will
79 | // resolve the promise that we'll inject into the request configuration.
80 | var abort = function() {
81 |
82 | abort.deferred.resolve();
83 |
84 | };
85 |
86 | abort.deferred = $q.defer();
87 |
88 | config.timeout = abort.deferred.promise;
89 |
90 | return( abort );
91 |
92 | }
93 |
94 |
95 | // I move values from the params and data arguments into the URL where
96 | // there is a match for labels. When the match occurs, the key-value
97 | // pairs are removed from the parent object and merged into the string
98 | // value of the URL.
99 | function interpolateUrl( url, params, data, removeTrailingSlash ) {
100 |
101 | // Make sure we have an object to work with - makes the rest of the
102 | // logic easier.
103 | params = ( params || {} );
104 | data = ( data || {} );
105 |
106 | // Strip out the delimiter fluff that is only there for readability
107 | // of the optional label paths.
108 | url = url.replace( /(\(\s*|\s*\)|\s*\|\s*)/g, "" );
109 |
110 | // Replace each label in the URL (ex, :userID).
111 | url = url.replace(
112 | /:([a-z]\w*)/gi,
113 | function( $0, label ) {
114 |
115 | // NOTE: Giving "data" precedence over "params".
116 | return( popFirstKey( data, params, label ) || "" );
117 |
118 | }
119 | );
120 |
121 | // Strip out any repeating slashes (but NOT the http:// version).
122 | url = url.replace( /(^|[^:])[\/]{2,}/g, "$1/" );
123 |
124 | // Strip out any trailing slash if necessary.
125 | if ( removeTrailingSlash ) {
126 |
127 | url = url.replace( /\/+$/i, "" );
128 |
129 | }
130 |
131 | return( url );
132 |
133 | }
134 |
135 |
136 | // I provide the default abort behavior, which doesn't do anything.
137 | function noopAbort() {
138 |
139 | if ( console && console.warn ) {
140 |
141 | console.warn( "This request cannot be aborted because the [timeout] property was already being used." );
142 |
143 | }
144 |
145 | }
146 |
147 |
148 | // I take 1..N objects and a key and perform a popKey() action on the
149 | // first object that contains the given key. If other objects in the list
150 | // also have the key, they are ignored.
151 | function popFirstKey( object1, object2, objectN, key ) {
152 |
153 | // Convert the arguments list into a true array so we can easily
154 | // pluck values from either end.
155 | var objects = Array.prototype.slice.call( arguments );
156 |
157 | // The key will always be the last item in the argument collection.
158 | var key = objects.pop();
159 |
160 | var object = null;
161 |
162 | // Iterate over the arguments, looking for the first object that
163 | // contains a reference to the given key.
164 | while ( object = objects.shift() ) {
165 |
166 | if ( object.hasOwnProperty( key ) ) {
167 |
168 | return( popKey( object, key ) );
169 |
170 | }
171 |
172 | }
173 |
174 | }
175 |
176 |
177 | // I delete the key from the given object and return the value.
178 | function popKey( object, key ) {
179 |
180 | var value = object[ key ];
181 |
182 | delete( object[ key ] );
183 |
184 | return( value );
185 |
186 | }
187 |
188 | }
189 | ]);
190 |
191 |
192 | // I provide a proxy for the given http service that injects the same URL in every
193 | // one of the outgoing requests. It is intended to be used with "httpi", but it has
194 | // no direct dependencies other than the general format of the $http configuration.
195 | module.factory(
196 | "HttpiResource",
197 | function httpiResourceFactory() {
198 |
199 | // I provide a resource that injects the given URL into the configuration
200 | // object before passing it off to the given http service.
201 | function Resource( http, url ) {
202 |
203 | // Store the http service.
204 | this._http = http;
205 |
206 | // Store the URL to inject.
207 | this._url = url;
208 |
209 | // I determine if the trailing slash should be kept in place.
210 | this._keepTrailingSlash = false;
211 |
212 | return( this );
213 |
214 | }
215 |
216 |
217 | // Define the instance methods.
218 | Resource.prototype = {
219 |
220 | // We have to explicitly set the constructor since we are overriding the
221 | // prototype object (which naturally holds the constructor).
222 | constructor: Resource,
223 |
224 |
225 | // ---
226 | // PUBLIC METHODS.
227 | // ---
228 |
229 |
230 | // I execute a DELETE request and return the http promise.
231 | delete: function( config ) {
232 |
233 | return( this._makeHttpRequest( "delete", config ) );
234 |
235 | },
236 |
237 |
238 | // I execute a GET request and return the http promise.
239 | get: function( config ) {
240 |
241 | return( this._makeHttpRequest( "get", config ) );
242 |
243 | },
244 |
245 |
246 | // I execute a HEAD request and return the http promise.
247 | head: function( config ) {
248 |
249 | return( this._makeHttpRequest( "head", config ) );
250 |
251 | },
252 |
253 |
254 | // I execute a JSONP request and return the http promise.
255 | jsonp: function( config ) {
256 |
257 | return( this._makeHttpRequest( "jsonp", config ) );
258 |
259 | },
260 |
261 |
262 | // I execute a POST request and return the http promise.
263 | post: function( config ) {
264 |
265 | return( this._makeHttpRequest( "post", config ) );
266 |
267 | },
268 |
269 |
270 | // I execute a PUT request and return the http promise.
271 | put: function( config ) {
272 |
273 | return( this._makeHttpRequest( "put", config ) );
274 |
275 | },
276 |
277 |
278 | // I set whether or not the resource should keep the trailing slash after
279 | // URL interpolation. Returns the resource reference for method chaining.
280 | setKeepTrailingSlash: function( newKeepTrailingSlash ) {
281 |
282 | this._keepTrailingSlash = newKeepTrailingSlash;
283 |
284 | // Return a reference to the instance.
285 | return( this );
286 |
287 | },
288 |
289 |
290 | // ---
291 | // PRIVATE METHODS.
292 | // ---
293 |
294 |
295 | // I prepare the configuration for the given type of request, then initiate
296 | // the underlying httpi request.
297 | _makeHttpRequest: function( method, config ) {
298 |
299 | // Ensure the configuration object exists.
300 | config = ( config || {} );
301 |
302 | // Inject resource-related properties.
303 | config.method = method;
304 | config.url = this._url;
305 |
306 | // Only inject trailing slash property if it's not already in the config.
307 | if ( ! config.hasOwnProperty( "keepTrailingSlash" ) ) {
308 |
309 | config.keepTrailingSlash = this._keepTrailingSlash
310 |
311 | }
312 |
313 | if ( config.method === "jsonp" ) {
314 |
315 | // Make sure the JSONP callback is defined somewhere in the config
316 | // object (AngularJS needs this to define the callback handle).
317 | this._paramJsonpCallback( config );
318 |
319 | }
320 |
321 | return( this._http( config ) );
322 |
323 | },
324 |
325 |
326 | // I make sure the callback marker is defined for the given JSONP request
327 | // configuration object.
328 | _paramJsonpCallback: function( config ) {
329 |
330 | var callbackName = "JSON_CALLBACK";
331 |
332 | // Check to see if it's in the URL already.
333 | if ( this._url.indexOf( callbackName ) !== -1 ) {
334 |
335 | return;
336 |
337 | }
338 |
339 | // Check to see if it's in the params already.
340 | if ( config.params ) {
341 |
342 | for ( var key in config.params ) {
343 |
344 | if (
345 | config.params.hasOwnProperty( key ) &&
346 | ( config.params[ key ] === callbackName )
347 | ) {
348 |
349 | return;
350 |
351 | }
352 |
353 | }
354 |
355 | // If there are no params, then make one so that we have a place to
356 | // inject the callback.
357 | } else {
358 |
359 | config.params = {}
360 |
361 | }
362 |
363 | // If we made it this far, then the current configuration does not
364 | // account for the JSONP callback. As such, let's inject it into the
365 | // params.
366 | config.params.callback = callbackName;
367 |
368 | }
369 |
370 | };
371 |
372 |
373 | // Return the constructor as the AngularJS factory result.
374 | return( Resource );
375 |
376 | }
377 | );
378 |
379 | })( angular );
--------------------------------------------------------------------------------
/example/vendor/angular-1.2.16.min.js:
--------------------------------------------------------------------------------
1 | /*
2 | AngularJS v1.2.16
3 | (c) 2010-2014 Google, Inc. http://angularjs.org
4 | License: MIT
5 | */
6 | (function(O,U,s){'use strict';function t(b){return function(){var a=arguments[0],c,a="["+(b?b+":":"")+a+"] http://errors.angularjs.org/1.2.16/"+(b?b+"/":"")+a;for(c=1;c").append(b).html();try{return 3===b[0].nodeType?K(c):c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/,
15 | function(a,b){return"<"+K(b)})}catch(d){return K(c)}}function Xb(b){try{return decodeURIComponent(b)}catch(a){}}function Yb(b){var a={},c,d;q((b||"").split("&"),function(b){b&&(c=b.split("="),d=Xb(c[0]),B(d)&&(b=B(c[1])?Xb(c[1]):!0,a[d]?M(a[d])?a[d].push(b):a[d]=[a[d],b]:a[d]=b))});return a}function Zb(b){var a=[];q(b,function(b,d){M(b)?q(b,function(b){a.push(za(d,!0)+(!0===b?"":"="+za(b,!0)))}):a.push(za(d,!0)+(!0===b?"":"="+za(b,!0)))});return a.length?a.join("&"):""}function wb(b){return za(b,
16 | !0).replace(/%26/gi,"&").replace(/%3D/gi,"=").replace(/%2B/gi,"+")}function za(b,a){return encodeURIComponent(b).replace(/%40/gi,"@").replace(/%3A/gi,":").replace(/%24/g,"$").replace(/%2C/gi,",").replace(/%20/g,a?"%20":"+")}function Wc(b,a){function c(a){a&&d.push(a)}var d=[b],e,g,f=["ng:app","ng-app","x-ng-app","data-ng-app"],h=/\sng[:\-]app(:\s*([\w\d_]+);?)?\s/;q(f,function(a){f[a]=!0;c(U.getElementById(a));a=a.replace(":","\\:");b.querySelectorAll&&(q(b.querySelectorAll("."+a),c),q(b.querySelectorAll("."+
17 | a+"\\:"),c),q(b.querySelectorAll("["+a+"]"),c))});q(d,function(a){if(!e){var b=h.exec(" "+a.className+" ");b?(e=a,g=(b[2]||"").replace(/\s+/g,",")):q(a.attributes,function(b){!e&&f[b.name]&&(e=a,g=b.value)})}});e&&a(e,g?[g]:[])}function $b(b,a){var c=function(){b=y(b);if(b.injector()){var c=b[0]===U?"document":ha(b);throw Pa("btstrpd",c);}a=a||[];a.unshift(["$provide",function(a){a.value("$rootElement",b)}]);a.unshift("ng");c=ac(a);c.invoke(["$rootScope","$rootElement","$compile","$injector","$animate",
18 | function(a,b,c,d,e){a.$apply(function(){b.data("$injector",d);c(b)(a)})}]);return c},d=/^NG_DEFER_BOOTSTRAP!/;if(O&&!d.test(O.name))return c();O.name=O.name.replace(d,"");Ea.resumeBootstrap=function(b){q(b,function(b){a.push(b)});c()}}function fb(b,a){a=a||"_";return b.replace(Xc,function(b,d){return(d?a:"")+b.toLowerCase()})}function xb(b,a,c){if(!b)throw Pa("areq",a||"?",c||"required");return b}function Ra(b,a,c){c&&M(b)&&(b=b[b.length-1]);xb(P(b),a,"not a function, got "+(b&&"object"==typeof b?
19 | b.constructor.name||"Object":typeof b));return b}function Aa(b,a){if("hasOwnProperty"===b)throw Pa("badname",a);}function bc(b,a,c){if(!a)return b;a=a.split(".");for(var d,e=b,g=a.length,f=0;f "+e[1]+a.replace(le,"<$1>$2>")+e[2];
26 | d.removeChild(d.firstChild);for(a=e[0];a--;)d=d.lastChild;a=0;for(e=d.childNodes.length;a=S?(c.preventDefault=null,c.stopPropagation=null,c.isDefaultPrevented=null):(delete c.preventDefault,delete c.stopPropagation,delete c.isDefaultPrevented)};c.elem=b;return c}function Ia(b){var a=typeof b,c;"object"==a&&null!==b?"function"==typeof(c=b.$$hashKey)?c=b.$$hashKey():c===s&&(c=b.$$hashKey=bb()):c=b;return a+":"+c}function Va(b){q(b,this.put,this)}function oc(b){var a,c;"function"==typeof b?(a=b.$inject)||(a=[],b.length&&(c=b.toString().replace(oe,
32 | ""),c=c.match(pe),q(c[1].split(qe),function(b){b.replace(re,function(b,c,d){a.push(d)})})),b.$inject=a):M(b)?(c=b.length-1,Ra(b[c],"fn"),a=b.slice(0,c)):Ra(b,"fn",!0);return a}function ac(b){function a(a){return function(b,c){if(X(b))q(b,Rb(a));else return a(b,c)}}function c(a,b){Aa(a,"service");if(P(b)||M(b))b=n.instantiate(b);if(!b.$get)throw Wa("pget",a);return m[a+h]=b}function d(a,b){return c(a,{$get:b})}function e(a){var b=[],c,d,g,h;q(a,function(a){if(!k.get(a)){k.put(a,!0);try{if(w(a))for(c=
33 | Sa(a),b=b.concat(e(c.requires)).concat(c._runBlocks),d=c._invokeQueue,g=0,h=d.length;g 4096 bytes)!"));else{if(l.cookie!==da)for(da=l.cookie,d=da.split("; "),Q={},g=0;gk&&this.remove(p.key),b},get:function(a){if(k").parent()[0])});var g=L(a,b,a,c,d,e);ma(a,"ng-scope");return function(b,c,d){xb(b,"scope");var e=c?Ja.clone.call(a):a;q(d,function(a,b){e.data("$"+b+"Controller",a)});d=0;for(var f=e.length;darguments.length&&
51 | (b=a,a=s);D&&(c=lb);return p(a,b,c)}var I,x,v,A,R,H,lb={},da;I=c===g?d:Ub(d,new Hb(y(g),d.$attr));x=I.$$element;if(Q){var T=/^\s*([@=&])(\??)\s*(\w*)\s*$/;f=y(g);H=e.$new(!0);ia&&ia===Q.$$originalDirective?f.data("$isolateScope",H):f.data("$isolateScopeNoTemplate",H);ma(f,"ng-isolate-scope");q(Q.scope,function(a,c){var d=a.match(T)||[],g=d[3]||c,f="?"==d[2],d=d[1],l,m,n,p;H.$$isolateBindings[c]=d+g;switch(d){case "@":I.$observe(g,function(a){H[c]=a});I.$$observers[g].$$scope=e;I[g]&&(H[c]=b(I[g])(e));
52 | break;case "=":if(f&&!I[g])break;m=r(I[g]);p=m.literal?xa:function(a,b){return a===b};n=m.assign||function(){l=H[c]=m(e);throw ja("nonassign",I[g],Q.name);};l=H[c]=m(e);H.$watch(function(){var a=m(e);p(a,H[c])||(p(a,l)?n(e,a=H[c]):H[c]=a);return l=a},null,m.literal);break;case "&":m=r(I[g]);H[c]=function(a){return m(e,a)};break;default:throw ja("iscp",Q.name,c,a);}})}da=p&&u;L&&q(L,function(a){var b={$scope:a===Q||a.$$isolateScope?H:e,$element:x,$attrs:I,$transclude:da},c;R=a.controller;"@"==R&&(R=
53 | I[a.name]);c=z(R,b);lb[a.name]=c;D||x.data("$"+a.name+"Controller",c);a.controllerAs&&(b.$scope[a.controllerAs]=c)});f=0;for(v=l.length;fG.priority)break;if(V=G.scope)A=A||G,G.templateUrl||(K("new/isolated scope",Q,G,Z),X(V)&&(Q=G));t=G.name;!G.templateUrl&&G.controller&&(V=G.controller,L=L||{},K("'"+t+"' controller",L[t],G,Z),L[t]=G);if(V=G.transclude)E=!0,G.$$tlb||(K("transclusion",T,G,Z),T=G),"element"==V?(D=!0,v=G.priority,
55 | V=H(c,ra,W),Z=d.$$element=y(U.createComment(" "+t+": "+d[t]+" ")),c=Z[0],mb(g,y(ya.call(V,0)),c),Xa=x(V,e,v,f&&f.name,{nonTlbTranscludeDirective:T})):(V=y(Eb(c)).contents(),Z.empty(),Xa=x(V,e));if(G.template)if(K("template",ia,G,Z),ia=G,V=P(G.template)?G.template(Z,d):G.template,V=Y(V),G.replace){f=G;V=Cb.test(V)?y(V):[];c=V[0];if(1!=V.length||1!==c.nodeType)throw ja("tplrt",t,"");mb(g,Z,c);S={$attr:{}};V=da(c,[],S);var $=a.splice(N+1,a.length-(N+1));Q&&pc(V);a=a.concat(V).concat($);B(d,S);S=a.length}else Z.html(V);
56 | if(G.templateUrl)K("template",ia,G,Z),ia=G,G.replace&&(f=G),J=C(a.splice(N,a.length-N),Z,d,g,Xa,l,n,{controllerDirectives:L,newIsolateScopeDirective:Q,templateDirective:ia,nonTlbTranscludeDirective:T}),S=a.length;else if(G.compile)try{O=G.compile(Z,d,Xa),P(O)?u(null,O,ra,W):O&&u(O.pre,O.post,ra,W)}catch(aa){m(aa,ha(Z))}G.terminal&&(J.terminal=!0,v=Math.max(v,G.priority))}J.scope=A&&!0===A.scope;J.transclude=E&&Xa;p.hasElementTranscludeDirective=D;return J}function pc(a){for(var b=0,c=a.length;bp.priority)&&-1!=p.restrict.indexOf(g)&&(n&&(p=Tb(p,{$$start:n,$$end:r})),b.push(p),k=p)}catch(F){m(F)}}return k}function B(a,b){var c=b.$attr,d=a.$attr,e=a.$$element;q(a,function(d,e){"$"!=e.charAt(0)&&(b[e]&&(d+=("style"===e?";":" ")+b[e]),a.$set(e,d,!0,c[e]))});q(b,function(b,g){"class"==g?(ma(e,b),a["class"]=(a["class"]?
58 | a["class"]+" ":"")+b):"style"==g?(e.attr("style",e.attr("style")+";"+b),a.style=(a.style?a.style+";":"")+b):"$"==g.charAt(0)||a.hasOwnProperty(g)||(a[g]=b,d[g]=c[g])})}function C(a,b,c,d,e,g,f,l){var k=[],m,r,z=b[0],u=a.shift(),F=D({},u,{templateUrl:null,transclude:null,replace:null,$$originalDirective:u}),x=P(u.templateUrl)?u.templateUrl(b,c):u.templateUrl;b.empty();n.get(v.getTrustedResourceUrl(x),{cache:p}).success(function(n){var p,J;n=Y(n);if(u.replace){n=Cb.test(n)?y(n):[];p=n[0];if(1!=n.length||
59 | 1!==p.nodeType)throw ja("tplrt",u.name,x);n={$attr:{}};mb(d,b,p);var v=da(p,[],n);X(u.scope)&&pc(v);a=v.concat(a);B(c,n)}else p=z,b.html(n);a.unshift(F);m=ia(a,p,c,e,b,u,g,f,l);q(d,function(a,c){a==p&&(d[c]=b[0])});for(r=L(b[0].childNodes,e);k.length;){n=k.shift();J=k.shift();var A=k.shift(),R=k.shift(),v=b[0];if(J!==z){var H=J.className;l.hasElementTranscludeDirective&&u.replace||(v=Eb(p));mb(A,y(J),v);ma(y(v),H)}J=m.transclude?Q(n,m.transclude):R;m(r,n,v,d,J)}k=null}).error(function(a,b,c,d){throw ja("tpload",
60 | d.url);});return function(a,b,c,d,e){k?(k.push(b),k.push(c),k.push(d),k.push(e)):m(r,b,c,d,e)}}function E(a,b){var c=b.priority-a.priority;return 0!==c?c:a.name!==b.name?a.namea.status?
69 | b:n.reject(b)}var d={method:"get",transformRequest:e.transformRequest,transformResponse:e.transformResponse},g=function(a){function b(a){var c;q(a,function(b,d){P(b)&&(c=b(),null!=c?a[d]=c:delete a[d])})}var c=e.headers,d=D({},a.headers),g,f,c=D({},c.common,c[K(a.method)]);b(c);b(d);a:for(g in c){a=K(g);for(f in d)if(K(f)===a)continue a;d[g]=c[g]}return d}(a);D(d,a);d.headers=g;d.method=Fa(d.method);(a=Ib(d.url)?b.cookies()[d.xsrfCookieName||e.xsrfCookieName]:s)&&(g[d.xsrfHeaderName||e.xsrfHeaderName]=
70 | a);var f=[function(a){g=a.headers;var b=uc(a.data,tc(g),a.transformRequest);E(a.data)&&q(g,function(a,b){"content-type"===K(b)&&delete g[b]});E(a.withCredentials)&&!E(e.withCredentials)&&(a.withCredentials=e.withCredentials);return z(a,b,g).then(c,c)},s],h=n.when(d);for(q(v,function(a){(a.request||a.requestError)&&f.unshift(a.request,a.requestError);(a.response||a.responseError)&&f.push(a.response,a.responseError)});f.length;){a=f.shift();var k=f.shift(),h=h.then(a,k)}h.success=function(a){h.then(function(b){a(b.data,
71 | b.status,b.headers,d)});return h};h.error=function(a){h.then(null,function(b){a(b.data,b.status,b.headers,d)});return h};return h}function z(b,c,g){function f(a,b,c,e){v&&(200<=a&&300>a?v.put(s,[a,b,sc(c),e]):v.remove(s));l(b,a,c,e);d.$$phase||d.$apply()}function l(a,c,d,e){c=Math.max(c,0);(200<=c&&300>c?p.resolve:p.reject)({data:a,status:c,headers:tc(d),config:b,statusText:e})}function k(){var a=db(r.pendingRequests,b);-1!==a&&r.pendingRequests.splice(a,1)}var p=n.defer(),z=p.promise,v,q,s=u(b.url,
72 | b.params);r.pendingRequests.push(b);z.then(k,k);(b.cache||e.cache)&&(!1!==b.cache&&"GET"==b.method)&&(v=X(b.cache)?b.cache:X(e.cache)?e.cache:F);if(v)if(q=v.get(s),B(q)){if(q.then)return q.then(k,k),q;M(q)?l(q[1],q[0],ba(q[2]),q[3]):l(q,200,{},"OK")}else v.put(s,z);E(q)&&a(b.method,s,c,f,g,b.timeout,b.withCredentials,b.responseType);return z}function u(a,b){if(!b)return a;var c=[];Sc(b,function(a,b){null===a||E(a)||(M(a)||(a=[a]),q(a,function(a){X(a)&&(a=qa(a));c.push(za(b)+"="+za(a))}))});0=S&&(!b.match(/^(get|post|head|put|delete|options)$/i)||!O.XMLHttpRequest))return new O.ActiveXObject("Microsoft.XMLHTTP");if(O.XMLHttpRequest)return new O.XMLHttpRequest;throw t("$httpBackend")("noxhr");}function Ud(){this.$get=["$browser","$window","$document",function(b,a,c){return ve(b,ue,b.defer,a.angular.callbacks,c[0])}]}function ve(b,a,c,d,e){function g(a,b){var c=e.createElement("script"),d=function(){c.onreadystatechange=
75 | c.onload=c.onerror=null;e.body.removeChild(c);b&&b()};c.type="text/javascript";c.src=a;S&&8>=S?c.onreadystatechange=function(){/loaded|complete/.test(c.readyState)&&d()}:c.onload=c.onerror=function(){d()};e.body.appendChild(c);return d}var f=-1;return function(e,l,k,m,n,p,r,z){function u(){v=f;A&&A();x&&x.abort()}function F(a,d,e,g,f){L&&c.cancel(L);A=x=null;0===d&&(d=e?200:"file"==sa(l).protocol?404:0);a(1223===d?204:d,e,g,f||"");b.$$completeOutstandingRequest(C)}var v;b.$$incOutstandingRequestCount();
76 | l=l||b.url();if("jsonp"==K(e)){var J="_"+(d.counter++).toString(36);d[J]=function(a){d[J].data=a};var A=g(l.replace("JSON_CALLBACK","angular.callbacks."+J),function(){d[J].data?F(m,200,d[J].data):F(m,v||-2);d[J]=Ea.noop})}else{var x=a(e);x.open(e,l,!0);q(n,function(a,b){B(a)&&x.setRequestHeader(b,a)});x.onreadystatechange=function(){if(x&&4==x.readyState){var a=null,b=null;v!==f&&(a=x.getAllResponseHeaders(),b="response"in x?x.response:x.responseText);F(m,v||x.status,b,a,x.statusText||"")}};r&&(x.withCredentials=
77 | !0);if(z)try{x.responseType=z}catch(s){if("json"!==z)throw s;}x.send(k||null)}if(0