diff options
| -rw-r--r-- | example/buzz/buzz.css | 0 | ||||
| -rw-r--r-- | example/buzz/buzz.html | 30 | ||||
| -rw-r--r-- | example/buzz/buzz.js | 19 | ||||
| -rw-r--r-- | src/AngularPublic.js | 5 | ||||
| -rw-r--r-- | src/Browser.js | 48 | ||||
| -rw-r--r-- | src/Resource.js | 3 | ||||
| -rw-r--r-- | test/BrowserSpecs.js | 28 | ||||
| -rw-r--r-- | test/ResourceSpec.js | 12 | ||||
| -rw-r--r-- | test/angular-mocks.js | 1 |
9 files changed, 125 insertions, 21 deletions
diff --git a/example/buzz/buzz.css b/example/buzz/buzz.css new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/example/buzz/buzz.css diff --git a/example/buzz/buzz.html b/example/buzz/buzz.html new file mode 100644 index 00000000..ee2b2bb9 --- /dev/null +++ b/example/buzz/buzz.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> +<html xmlns:ng="http://angularjs.org"> + <head> + <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.js"></script> + <script type="text/javascript" src="../../src/angular-bootstrap.js#autobind"></script> + <script type="text/javascript" src="buzz.js"></script> + <link rel="stylesheet" type="text/css" href="style.css"/> + </head> + <body ng:init="$window.$root = this" ng:controller="BuzzController"> + <div class="bar"> + <input type="text" name="userId"/> + <button ng:click="$location.hashPath = userId">fetch</button> + </div> + <ul> + <li ng:repeat="item in activities.data.items"> + <img src="{{item.actor.thumbnailUrl}}"/> + <a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a> + {{item.object.content | html}} + <a href="">Replies: {{item.links.replies[0].count}}</a> + <ul> + <li ng:repeat="reply in item.replies.items"> + <img src="{{reply.actor.thumbnailUrl}}"/> + <a href="{{reply.actor.profileUrl}}">{{reply.actor.name}}</a> + {{reply.content | html}} + </li> + </ul> + </li> + </ul> + </body> +</html> diff --git a/example/buzz/buzz.js b/example/buzz/buzz.js new file mode 100644 index 00000000..871982d7 --- /dev/null +++ b/example/buzz/buzz.js @@ -0,0 +1,19 @@ +angular.service('myApplication', function($resource){ + this.Activity = $resource( + 'https://www.googleapis.com/buzz/v1/activities/:userId/:visibility/:activityId/:comments', + {alt:'json', callback:'JSON_CALLBACK'}, + { + get: {method:'JSON', params:{visibility:'@self'}}, + replies: {method:'JSON', params:{visibility:'@self', comments:'@comments'}} + }); +}, {inject:['$resource']}); + +function BuzzController(){ + this.$watch('$location.hashPath', this.userChange); +} +BuzzController.prototype = { + userChange: function(){ + this.userId = this.$location.hashPath; + this.activities = this.Activity.get({userId:this.userId}); + } +}; diff --git a/src/AngularPublic.js b/src/AngularPublic.js index e2e576fd..7b093f88 100644 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -1,7 +1,10 @@ var browserSingleton; angularService('$browser', function browserFactory(){ if (!browserSingleton) { - browserSingleton = new Browser(window.location, window.document); + browserSingleton = new Browser( + window.location, + jqLite(window.document), + jqLite(window.document.getElementsByTagName('head')[0])); browserSingleton.startUrlWatcher(); browserSingleton.bind(); } diff --git a/src/Browser.js b/src/Browser.js index 0552b3ae..3299540c 100644 --- a/src/Browser.js +++ b/src/Browser.js @@ -2,7 +2,7 @@ // Browser ////////////////////////////// -function Browser(location, document) { +function Browser(location, document, head) { this.delay = 50; this.expectedUrl = location.href; this.urlListeners = []; @@ -21,8 +21,9 @@ function Browser(location, document) { }; this.location = location; - this.document = jqLite(document); - this.body = jqLite(document.body); + this.document = document; + this.head = head; + this.idCounter = 0; } Browser.prototype = { @@ -58,21 +59,34 @@ Browser.prototype = { callback = post; post = null; } - var xhr = new this.XHR(), - self = this; - xhr.open(method, url, true); - this.outstandingRequests.count ++; - xhr.onreadystatechange = function() { - if (xhr.readyState == 4) { - try { - callback(xhr.status || 200, xhr.responseText); - } finally { - self.outstandingRequests.count--; - self.processRequestCallbacks(); + if (lowercase(method) == 'json') { + var callbackId = "angular_" + Math.random() + '_' + (this.idCounter++); + callbackId = callbackId.replace(/\d\./, ''); + var script = this.document[0].createElement('script'); + script.type = 'text/javascript'; + script.src = url.replace('JSON_CALLBACK', callbackId); + this.head.append(script); + window[callbackId] = function(data){ + delete window[callbackId]; + callback(200, data); + }; + } else { + var xhr = new this.XHR(), + self = this; + xhr.open(method, url, true); + this.outstandingRequests.count ++; + xhr.onreadystatechange = function() { + if (xhr.readyState == 4) { + try { + callback(xhr.status || 200, xhr.responseText); + } finally { + self.outstandingRequests.count--; + self.processRequestCallbacks(); + } } - } - }; - xhr.send(post || ''); + }; + xhr.send(post || ''); + } }, processRequestCallbacks: function(){ diff --git a/src/Resource.js b/src/Resource.js index 1279dc54..f4f26ebd 100644 --- a/src/Resource.js +++ b/src/Resource.js @@ -28,6 +28,7 @@ Route.prototype = { query.push(encodeURI(key) + '=' + encodeURI(value)); } }); + url = url.replace(/\/*$/, ''); return url + (query.length ? '?' + query.join('&') : ''); } }; @@ -88,7 +89,7 @@ ResourceFactory.prototype = { throw "Expected between 0-3 arguments [params, data, callback], got " + arguments.length + " arguments."; } - var value = action.isArray ? [] : new Resource(data) + var value = action.isArray ? [] : new Resource(data); self.xhr( action.method, route.url(extend({}, action.params || {}, extractParams(data), params)), diff --git a/test/BrowserSpecs.js b/test/BrowserSpecs.js index 3ce158b4..a9f61a6b 100644 --- a/test/BrowserSpecs.js +++ b/test/BrowserSpecs.js @@ -1,10 +1,15 @@ describe('browser', function(){ - var browser, location; + var browser, location, head; beforeEach(function(){ location = {href:"http://server", hash:""}; - browser = new Browser(location, {}); + document = jqLite(window.document); + head = { + scripts: [], + append: function(node){head.scripts.push(node);} + }; + browser = new Browser(location, jqLite(window.document), head); browser.setTimeout = noop; }); @@ -45,4 +50,23 @@ describe('browser', function(){ }); }); + describe('xhr', function(){ + describe('JSON', function(){ + it('should add script tag for request', function() { + var log = ""; + browser.xhr('JSON', 'http://example.org/path?cb=JSON_CALLBACK', function(code, data){ + log += code + ':' + data + ';'; + }); + expect(head.scripts.length).toEqual(1); + var url = head.scripts[0].src.split('?cb='); + expect(url[0]).toEqual('http://example.org/path'); + expect(typeof window[url[1]]).toEqual('function'); + window[url[1]]('data'); + expect(log).toEqual('200:data;'); + expect(typeof window[url[1]]).toEqual('undefined'); + + }); + }); + }); + }); diff --git a/test/ResourceSpec.js b/test/ResourceSpec.js index 4882e70e..6e32ce18 100644 --- a/test/ResourceSpec.js +++ b/test/ResourceSpec.js @@ -28,6 +28,18 @@ describe("resource", function() { resource.route('URL').query(); }); + it('should ignore slashes of undefinend parameters', function(){ + var R = resource.route('/Path/:a/:b/:c'); + xhr.expectGET('/Path').respond({}); + xhr.expectGET('/Path/1').respond({}); + xhr.expectGET('/Path/2/3').respond({}); + xhr.expectGET('/Path/4/5/6').respond({}); + R.get({}); + R.get({a:1}); + R.get({a:2, b:3}); + R.get({a:4, b:5, c:6}); + }); + it("should build resource with default param", function(){ xhr.expectGET('/Order/123/Line/456.visa?minimum=0.05').respond({id:'abc'}); var LineItem = resource.route('/Order/:orderId/Line/:id:verb', {orderId: '123', id: '@id.key', verb:'.visa', minimum:0.05}); diff --git a/test/angular-mocks.js b/test/angular-mocks.js index 8838b2cd..bac2e800 100644 --- a/test/angular-mocks.js +++ b/test/angular-mocks.js @@ -66,6 +66,7 @@ function MockBrowser() { self.xhr.expectPOST = angular.bind(self, self.xhr.expect, 'POST'); self.xhr.expectDELETE = angular.bind(self, self.xhr.expect, 'DELETE'); self.xhr.expectPUT = angular.bind(self, self.xhr.expect, 'PUT'); + self.xhr.expectJSON = angular.bind(self, self.xhr.expect, 'JSON'); self.xhr.flush = function() { while(requests.length) { requests.pop()(); |
