From 6e8d2634e1c910cc39ffd1a443e3ac06dfab119e Mon Sep 17 00:00:00 2001 From: Mike Brevoort Date: Wed, 5 Jun 2013 23:51:29 -0600 Subject: [PATCH] fix(noConflict): address global JSONP conflicts and window.angular cannibalization Eliminate angular.callbacks and use random callback handles on window to eliminate multiple angular version conflicts, and be sure to start with an empty window.angular object rather than polluting existing window.angular --- src/Angular.js | 2 +- src/ng/httpBackend.js | 18 +++++++++--------- test/ng/httpBackendSpec.js | 27 ++++++++++++++------------- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/Angular.js b/src/Angular.js index 952e7a1d41a9..d3b299ddad32 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -58,7 +58,7 @@ var /** holds major version number for IE or NaN for real browsers */ _angular = window.angular, /** @name angular */ - angular = window.angular || (window.angular = {}), + angular = window.angular = {}, angularModule, nodeName_, uid = ['0', '0', '0']; diff --git a/src/ng/httpBackend.js b/src/ng/httpBackend.js index 5b9657057e66..31b66f17e366 100644 --- a/src/ng/httpBackend.js +++ b/src/ng/httpBackend.js @@ -25,12 +25,12 @@ var XHR = window.XMLHttpRequest || function() { */ function $HttpBackendProvider() { this.$get = ['$browser', '$window', '$document', function($browser, $window, $document) { - return createHttpBackend($browser, XHR, $browser.defer, $window.angular.callbacks, + return createHttpBackend($browser, $window, XHR, $browser.defer, $document[0], $window.location.protocol.replace(':', '')); }]; } -function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, locationProtocol) { +function createHttpBackend($browser, $window, XHR, $browserDefer, rawDocument, locationProtocol) { // TODO(vojta): fix the signature return function(method, url, post, callback, headers, timeout, withCredentials, responseType) { var status; @@ -38,19 +38,19 @@ function createHttpBackend($browser, XHR, $browserDefer, callbacks, rawDocument, url = url || $browser.url(); if (lowercase(method) == 'jsonp') { - var callbackId = '_' + (callbacks.counter++).toString(36); - callbacks[callbackId] = function(data) { - callbacks[callbackId].data = data; + var callbackHanger = 'ngJsonpCallback_' + Math.random().toString(36).substring(7); + $window[callbackHanger] = function(data) { + $window[callbackHanger].data = data; }; - var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', 'angular.callbacks.' + callbackId), + var jsonpDone = jsonpReq(url.replace('JSON_CALLBACK', callbackHanger), function() { - if (callbacks[callbackId].data) { - completeRequest(callback, 200, callbacks[callbackId].data); + if ($window[callbackHanger].data) { + completeRequest(callback, 200, $window[callbackHanger].data); } else { completeRequest(callback, status || -2); } - delete callbacks[callbackId]; + delete $window[callbackHanger]; }); } else { var xhr = new XHR(); diff --git a/test/ng/httpBackendSpec.js b/test/ng/httpBackendSpec.js index c65ab2e17c5b..e26075d90e75 100644 --- a/test/ng/httpBackendSpec.js +++ b/test/ng/httpBackendSpec.js @@ -1,6 +1,6 @@ describe('$httpBackend', function() { - var $backend, $browser, callbacks, + var $backend, $browser, $window, callbacks, xhr, fakeDocument, callback, fakeTimeoutId = 0; @@ -36,6 +36,7 @@ describe('$httpBackend', function() { beforeEach(inject(function($injector) { callbacks = {counter: 0}; $browser = $injector.get('$browser'); + $window = $injector.get('$window'); fakeDocument = { $$scripts: [], createElement: jasmine.createSpy('createElement').andCallFake(function() { @@ -53,7 +54,7 @@ describe('$httpBackend', function() { }) } }; - $backend = createHttpBackend($browser, MockXhr, fakeTimeout, callbacks, fakeDocument); + $backend = createHttpBackend($browser, $window, MockXhr, fakeTimeout, fakeDocument); callback = jasmine.createSpy('done'); })); @@ -200,7 +201,7 @@ describe('$httpBackend', function() { expect(response).toBe('response'); }); - $backend = createHttpBackend($browser, SyncXhr); + $backend = createHttpBackend($browser, $window, SyncXhr); $backend('GET', '/url', null, callback); expect(callback).toHaveBeenCalledOnce(); }); @@ -232,7 +233,7 @@ describe('$httpBackend', function() { describe('JSONP', function() { - var SCRIPT_URL = /([^\?]*)\?cb=angular\.callbacks\.(.*)/; + var SCRIPT_URL = /([^\?]*)\?cb=ngJsonpCallback_(.*)/; it('should add script tag for JSONP request', function() { @@ -243,12 +244,12 @@ describe('$httpBackend', function() { $backend('JSONP', 'http://example.org/path?cb=JSON_CALLBACK', null, callback); expect(fakeDocument.$$scripts.length).toBe(1); - var script = fakeDocument.$$scripts.shift(), url = script.src.match(SCRIPT_URL); expect(url[1]).toBe('http://example.org/path'); - callbacks[url[2]]('some-data'); + var callbackHanger = 'ngJsonpCallback_' + url[2]; + $window[callbackHanger]('some-data'); if (script.onreadystatechange) { script.readyState = 'complete'; @@ -267,9 +268,9 @@ describe('$httpBackend', function() { var script = fakeDocument.$$scripts.shift(), - callbackId = script.src.match(SCRIPT_URL)[2]; + callbackHanger = 'ngJsonpCallback_' + script.src.match(SCRIPT_URL)[2]; - callbacks[callbackId]('some-data'); + $window[callbackHanger]('some-data'); if (script.onreadystatechange) { script.readyState = 'complete'; @@ -278,7 +279,7 @@ describe('$httpBackend', function() { script.onload() } - expect(callbacks[callbackId]).toBeUndefined(); + expect($window[callbackHanger]).toBeUndefined(); expect(fakeDocument.body.removeChild).toHaveBeenCalledOnceWith(script); }); @@ -344,7 +345,7 @@ describe('$httpBackend', function() { it('should convert 0 to 200 if content', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'http'); + $backend = createHttpBackend($browser, $window, MockXhr, null, null, 'http'); $backend('GET', 'file:///whatever/index.html', null, callback); respond(0, 'SOME CONTENT'); @@ -355,7 +356,7 @@ describe('$httpBackend', function() { it('should convert 0 to 200 if content - relative url', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'file'); + $backend = createHttpBackend($browser, $window, MockXhr, null, null, 'file'); $backend('GET', '/whatever/index.html', null, callback); respond(0, 'SOME CONTENT'); @@ -366,7 +367,7 @@ describe('$httpBackend', function() { it('should convert 0 to 404 if no content', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'http'); + $backend = createHttpBackend($browser, $window, MockXhr, null, null, 'http'); $backend('GET', 'file:///whatever/index.html', null, callback); respond(0, ''); @@ -377,7 +378,7 @@ describe('$httpBackend', function() { it('should convert 0 to 200 if content - relative url', function() { - $backend = createHttpBackend($browser, MockXhr, null, null, null, 'file'); + $backend = createHttpBackend($browser, $window, MockXhr, null, null, 'file'); $backend('GET', '/whatever/index.html', null, callback); respond(0, '');