added jsonp to resources

This commit is contained in:
Misko Hevery 2010-07-22 11:18:32 -07:00
parent b5bbfaeb80
commit 849a05b5a5
9 changed files with 125 additions and 21 deletions

0
example/buzz/buzz.css Normal file
View file

30
example/buzz/buzz.html Normal file
View file

@ -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>

19
example/buzz/buzz.js Normal file
View file

@ -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});
}
};

View file

@ -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();
}

View file

@ -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(){

View file

@ -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)),

View file

@ -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');
});
});
});
});

View file

@ -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});

View file

@ -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()();