diff --git a/docs/content/guide/dev_guide.bootstrap.auto_bootstrap.ngdoc b/docs/content/guide/dev_guide.bootstrap.auto_bootstrap.ngdoc index 10466d5ec0c4..438b3d3889ad 100644 --- a/docs/content/guide/dev_guide.bootstrap.auto_bootstrap.ngdoc +++ b/docs/content/guide/dev_guide.bootstrap.auto_bootstrap.ngdoc @@ -53,8 +53,7 @@ appending `#autobind` to the ` +
@@ -67,22 +66,24 @@ appending `#autobind` to the ` + + +
+ Hello {{'world'}}! +
+ + + -Optionally, any of the filename formats above can be prepended with a relative or absolute URL that -ends with `/`. ## Global Angular Object diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js index 78b5a6585206..6ca6bdcf9b4e 100644 --- a/docs/src/templates/docs.js +++ b/docs/src/templates/docs.js @@ -1,5 +1,5 @@ -DocsController.$inject = ['$location', '$browser', '$window', '$cookies']; -function DocsController($location, $browser, $window, $cookies) { +DocsController.$inject = ['$location', '$window', '$cookies']; +function DocsController($location, $window, $cookies) { window.$root = this.$root; var scope = this, diff --git a/example/personalLog/scenario/personalLogScenario.js b/example/personalLog/scenario/personalLogScenario.js index fe6388b4e299..355761bd09f2 100644 --- a/example/personalLog/scenario/personalLogScenario.js +++ b/example/personalLog/scenario/personalLogScenario.js @@ -16,7 +16,7 @@ describe('personal log', function() { element('form input[type="submit"]').click(); expect(repeater('ul li').count()).toEqual(1); - expect(repeater('ul li').column('log.msg')).toEqual('my first message'); + expect(repeater('ul li').column('log.msg')).toEqual(['my first message']); //create second msg input('newMsg').enter('my second message'); @@ -38,7 +38,7 @@ describe('personal log', function() { element('ul li a:eq(1)').click(); expect(repeater('ul li').count()).toEqual(1); - expect(repeater('ul li').column('log.msg')).toEqual('my second message'); + expect(repeater('ul li').column('log.msg')).toEqual(['my second message']); element('ul li a:eq(0)').click(); expect(repeater('ul li').count()).toEqual(0); @@ -66,7 +66,7 @@ describe('personal log', function() { browser().reload(); - expect(repeater('ul li').column('log.msg')).toEqual('my persistent message'); + expect(repeater('ul li').column('log.msg')).toEqual(['my persistent message']); expect(repeater('ul li').count()).toEqual(1); }); }); @@ -85,10 +85,11 @@ angular.scenario.dsl('clearCookies', function() { $cookies = rootScope.$service('$cookies'), cookieName; - for (cookieName in $cookies) { - delete $cookies[cookieName]; - } - rootScope.$eval(); + rootScope.$apply(function() { + for (cookieName in $cookies) { + delete $cookies[cookieName]; + } + }); done(); }); diff --git a/src/Angular.js b/src/Angular.js index 256a119c1308..ab031049ea9e 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -14,7 +14,7 @@ if (typeof document.getAttribute == $undefined) * @param {string} string String to be converted to lowercase. * @returns {string} Lowercased string. */ -var lowercase = function(string){ return isString(string) ? string.toLowerCase() : string; }; +var lowercase = function(string){return isString(string) ? string.toLowerCase() : string;}; /** @@ -26,17 +26,17 @@ var lowercase = function(string){ return isString(string) ? string.toLowerCase() * @param {string} string String to be converted to uppercase. * @returns {string} Uppercased string. */ -var uppercase = function(string){ return isString(string) ? string.toUpperCase() : string; }; +var uppercase = function(string){return isString(string) ? string.toUpperCase() : string;}; var manualLowercase = function(s) { return isString(s) - ? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32); }) + ? s.replace(/[A-Z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) | 32);}) : s; }; var manualUppercase = function(s) { return isString(s) - ? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32); }) + ? s.replace(/[a-z]/g, function(ch) {return fromCharCode(ch.charCodeAt(0) & ~32);}) : s; }; @@ -49,12 +49,12 @@ if ('i' !== 'I'.toLowerCase()) { uppercase = manualUppercase; } -function fromCharCode(code) { return String.fromCharCode(code); } +function fromCharCode(code) {return String.fromCharCode(code);} /** * Creates the element for IE8 and below to allow styling of widgets - * (http://ejohn.org/blog/html5-shiv/). This hack works only if angular is - * included synchronously at the top of the document before IE sees any + * (http://ejohn.org/blog/html5-shiv/). This hack works only if angular is + * included synchronously at the top of the document before IE sees any * unknown elements. See regression/issue-584.html. * * @param {string} elementName Name of the widget. @@ -116,7 +116,6 @@ var _undefined = undefined, angularService = extensionMap(angular, 'service'), angularCallbacks = extensionMap(angular, 'callbacks'), nodeName_, - rngScript = /^(|.*\/)angular(-.*?)?(\.min)?.js(\?[^#]*)?(#(.*))?$/, uid = ['0', '0', '0'], DATE_ISOSTRING_LN = 24; @@ -295,7 +294,7 @@ function noop() {} function identity($) {return $;} -function valueFn(value) {return function() { return value; };} +function valueFn(value) {return function() {return value;};} function extensionMap(angular, name, transform) { var extPoint; @@ -319,7 +318,7 @@ function extensionMap(angular, name, transform) { * @param {*} value Reference to check. * @returns {boolean} True if `value` is undefined. */ -function isUndefined(value){ return typeof value == $undefined; } +function isUndefined(value){return typeof value == $undefined;} /** @@ -333,7 +332,7 @@ function isUndefined(value){ return typeof value == $undefined; } * @param {*} value Reference to check. * @returns {boolean} True if `value` is defined. */ -function isDefined(value){ return typeof value != $undefined; } +function isDefined(value){return typeof value != $undefined;} /** @@ -348,7 +347,7 @@ function isDefined(value){ return typeof value != $undefined; } * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Object` but not `null`. */ -function isObject(value){ return value!=null && typeof value == $object;} +function isObject(value){return value!=null && typeof value == $object;} /** @@ -362,7 +361,7 @@ function isObject(value){ return value!=null && typeof value == $object;} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `String`. */ -function isString(value){ return typeof value == $string;} +function isString(value){return typeof value == $string;} /** @@ -376,7 +375,7 @@ function isString(value){ return typeof value == $string;} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Number`. */ -function isNumber(value){ return typeof value == $number;} +function isNumber(value){return typeof value == $number;} /** @@ -390,7 +389,7 @@ function isNumber(value){ return typeof value == $number;} * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Date`. */ -function isDate(value){ return value instanceof Date; } +function isDate(value){return value instanceof Date;} /** @@ -404,7 +403,7 @@ function isDate(value){ return value instanceof Date; } * @param {*} value Reference to check. * @returns {boolean} True if `value` is an `Array`. */ -function isArray(value) { return value instanceof Array; } +function isArray(value) {return value instanceof Array;} /** @@ -418,7 +417,7 @@ function isArray(value) { return value instanceof Array; } * @param {*} value Reference to check. * @returns {boolean} True if `value` is a `Function`. */ -function isFunction(value){ return typeof value == 'function';} +function isFunction(value){return typeof value == 'function';} /** @@ -432,8 +431,8 @@ function isWindow(obj) { return obj && obj.document && obj.location && obj.alert && obj.setInterval; } -function isBoolean(value) { return typeof value == $boolean; } -function isTextNode(node) { return nodeName_(node) == '#text'; } +function isBoolean(value) {return typeof value == $boolean;} +function isTextNode(node) {return nodeName_(node) == '#text';} function trim(value) { return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value; @@ -953,35 +952,30 @@ function angularInit(config, document){ var autobind = config.autobind; if (autobind) { - var element = isString(autobind) ? document.getElementById(autobind) : document, - scope = compile(element)(createScope()), - $browser = scope.$service('$browser'); - - if (config.css) - $browser.addCss(config.base_url + config.css); - scope.$apply(); + var element = isString(autobind) ? document.getElementById(autobind) : document; + compile(element)().$apply(); } } function angularJsConfig(document) { bindJQuery(); - var scripts = document.getElementsByTagName("script"), + var scripts = document.getElementsByTagName('script'), + script = scripts[scripts.length-1], + scriptSrc = script.src, config = {}, - match; - for(var j = 0; j < scripts.length; j++) { - match = (scripts[j].src || "").match(rngScript); - if (match) { - config.base_url = match[1]; - extend(config, parseKeyValue(match[6])); - eachAttribute(jqLite(scripts[j]), function(value, name){ - if (/^ng:/.exec(name)) { - name = name.substring(3).replace(/-/g, '_'); - value = value || true; - config[name] = value; - } - }); + hashPos; + + hashPos = scriptSrc.indexOf('#'); + if (hashPos != -1) extend(config, parseKeyValue(scriptSrc.substr(hashPos+1))); + + eachAttribute(jqLite(script), function(value, name){ + if (/^ng:/.exec(name)) { + name = name.substring(3).replace(/-/g, '_'); + value = value || true; + config[name] = value; } - } + }); + return config; } diff --git a/src/angular-bootstrap.js b/src/angular-bootstrap.js index 7a1752d278b5..fb2acbeb5796 100644 --- a/src/angular-bootstrap.js +++ b/src/angular-bootstrap.js @@ -99,9 +99,7 @@ // empty the cache to prevent mem leaks globalVars = {}; - var config = angularJsConfig(document); - - angularInit(config, document); + angularInit({autobind:true}, document); } if (window.addEventListener) { diff --git a/src/angular.suffix b/src/angular.suffix index e8bb83b7ef93..d38d3130dc35 100644 --- a/src/angular.suffix +++ b/src/angular.suffix @@ -1,6 +1,8 @@ + var config = angularJsConfig(document); + jqLiteWrap(document).ready(function() { - angularInit(angularJsConfig(document), document); + angularInit(config, document); }); })(window, document); diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 5b0a3466c9ee..7831539d215a 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -228,181 +228,97 @@ describe('angular', function() { }); - describe ('rngScript', function() { - it('should match angular.js', function() { - expect('angular.js'.match(rngScript)).not.toBeNull(); - expect('../angular.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular.js'.match(rngScript)).not.toBeNull(); - - expect('foo.js'.match(rngScript)).toBeNull(); - expect('foo/foo.js'.match(rngScript)).toBeNull(); - expect('my-angular-app.js'.match(rngScript)).toBeNull(); - expect('foo/../my-angular-app.js'.match(rngScript)).toBeNull(); - }); - - it('should match angular.min.js', function() { - expect('angular.min.js'.match(rngScript)).not.toBeNull(); - expect('../angular.min.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular.min.js'.match(rngScript)).not.toBeNull(); - - expect('my-angular-app.min.js'.match(rngScript)).toBeNull(); - expect('foo/../my-angular-app.min.js'.match(rngScript)).toBeNull(); - }); - - it('should match angular-bootstrap.js', function() { - expect('angular-bootstrap.js'.match(rngScript)).not.toBeNull(); - expect('../angular-bootstrap.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-bootstrap.js'.match(rngScript)).not.toBeNull(); - - expect('my-angular-app-bootstrap.js'.match(rngScript)).toBeNull(); - expect('foo/../my-angular-app-bootstrap.js'.match(rngScript)).toBeNull(); - }); - - it('should match angular-0.9.0.js', function() { - expect('angular-0.9.0.js'.match(rngScript)).not.toBeNull(); - expect('../angular-0.9.0.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-0.9.0.js'.match(rngScript)).not.toBeNull(); - - expect('my-angular-app-0.9.0.js'.match(rngScript)).toBeNull(); - expect('foo/../my-angular-app-0.9.0.js'.match(rngScript)).toBeNull(); - }); - - it('should match angular-0.9.0.min.js', function() { - expect('angular-0.9.0.min.js'.match(rngScript)).not.toBeNull(); - expect('../angular-0.9.0.min.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-0.9.0.min.js'.match(rngScript)).not.toBeNull(); - - expect('my-angular-app-0.9.0.min.js'.match(rngScript)).toBeNull(); - expect('foo/../my-angular-app-0.9.0.min.js'.match(rngScript)).toBeNull(); - }); - - it('should match angular-0.9.0-de0a8612.js', function() { - expect('angular-0.9.0-de0a8612.js'.match(rngScript)).not.toBeNull(); - expect('../angular-0.9.0-de0a8612.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-0.9.0-de0a8612.js'.match(rngScript)).not.toBeNull(); - - expect('my-angular-app-0.9.0-de0a8612.js'.match(rngScript)).toBeNull(); - expect('foo/../my-angular-app-0.9.0-de0a8612.js'.match(rngScript)).toBeNull(); - }); - - it('should match angular-0.9.0-de0a8612.min.js', function() { - expect('angular-0.9.0-de0a8612.min.js'.match(rngScript)).not.toBeNull(); - expect('../angular-0.9.0-de0a8612.min.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-0.9.0-de0a8612.min.js'.match(rngScript)).not.toBeNull(); - - expect('my-angular-app-0.9.0-de0a8612.min.js'.match(rngScript)).toBeNull(); - expect('foo/../my-angular-app-0.9.0-de0a8612.min.js'.match(rngScript)).toBeNull(); - }); - - it('should match angular-scenario.js', function() { - expect('angular-scenario.js'.match(rngScript)).not.toBeNull(); - expect('angular-scenario.min.js'.match(rngScript)).not.toBeNull(); - expect('../angular-scenario.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-scenario.min.js'.match(rngScript)).not.toBeNull(); - }); - - it('should match angular-scenario-0.9.0(.min).js', function() { - expect('angular-scenario-0.9.0.js'.match(rngScript)).not.toBeNull(); - expect('angular-scenario-0.9.0.min.js'.match(rngScript)).not.toBeNull(); - expect('../angular-scenario-0.9.0.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-scenario-0.9.0.min.js'.match(rngScript)).not.toBeNull(); - }); - - it('should match angular-scenario-0.9.0-de0a8612(.min).js', function() { - expect('angular-scenario-0.9.0-de0a8612.js'.match(rngScript)).not.toBeNull(); - expect('angular-scenario-0.9.0-de0a8612.min.js'.match(rngScript)).not.toBeNull(); - expect('../angular-scenario-0.9.0-de0a8612.js'.match(rngScript)).not.toBeNull(); - expect('foo/angular-scenario-0.9.0-de0a8612.min.js'.match(rngScript)).not.toBeNull(); - }); - }); + describe('angularJsConfig', function() { + it('should always consider angular.js script tag to be the last script tag', function() { + var doc = { + getElementsByTagName: function(tagName) { + expect(tagName).toEqual('script'); + return [{nodeName: 'SCRIPT', src: 'random.js', + attributes: [{name: 'ng:autobind', value: 'wrong'}]}, + {nodeName: 'SCRIPT', src: 'angular.js', + attributes: [{name: 'ng:autobind', value: 'correct'}]}]; + } + }; + expect(angularJsConfig(doc)).toEqual({autobind: 'correct'}); - describe('angularJsConfig', function() { - it('should find angular.js script tag and config', function() { - var doc = { getElementsByTagName: function(tagName) { - expect(tagName).toEqual('script'); - return [{nodeName: 'SCRIPT', src: 'random.js'}, - {nodeName: 'SCRIPT', src: 'angular.js'}, - {nodeName: 'SCRIPT', src: 'my-angular-app.js'}]; - } + doc = { + getElementsByTagName: function(tagName) { + expect(tagName).toEqual('script'); + return [{nodeName: 'SCRIPT', src: 'angular.js', + attributes: [{name: 'ng:autobind', value: 'wrong'}]}, + {nodeName: 'SCRIPT', src: 'concatinatedAndObfuscadedScriptWithOurScript.js', + attributes: [{name: 'ng:autobind', value: 'correct'}]}]; + } }; - expect(angularJsConfig(doc)).toEqual({base_url: ''}); + expect(angularJsConfig(doc)).toEqual({autobind: 'correct'}); }); - it('should extract angular config from the ng: attributes', - function() { + it('should extract angular config from the ng: attributes', function() { var doc = { getElementsByTagName: function(tagName) { expect(lowercase(tagName)).toEqual('script'); - return [{nodeName: 'SCRIPT', + return [{ + nodeName: 'SCRIPT', src: 'angularjs/angular.js', attributes: [{name: 'ng:autobind', value:'elementIdToCompile'}, {name: 'ng:css', value: 'css/my_custom_angular.css'}] }]; }}; - expect(angularJsConfig(doc)).toEqual({base_url: 'angularjs/', + expect(angularJsConfig(doc)).toEqual({ autobind: 'elementIdToCompile', - css: 'css/my_custom_angular.css'}); + css: 'css/my_custom_angular.css' + }); }); it('should extract angular config and default autobind value to true if present', function() { var doc = { getElementsByTagName: function(tagName) { expect(lowercase(tagName)).toEqual('script'); - return [{nodeName: 'SCRIPT', + return [{ + nodeName: 'SCRIPT', src: 'angularjs/angular.js', attributes: [{name: 'ng:autobind', value:undefined}]}]; }}; - expect(angularJsConfig(doc)).toEqual({autobind: true, - base_url: 'angularjs/'}); + expect(angularJsConfig(doc)).toEqual({autobind: true}); }); it('should extract angular autobind config from the script hashpath attributes', function() { var doc = { getElementsByTagName: function(tagName) { expect(lowercase(tagName)).toEqual('script'); - return [{nodeName: 'SCRIPT', + return [{ + nodeName: 'SCRIPT', src: 'angularjs/angular.js#autobind'}]; }}; - expect(angularJsConfig(doc)).toEqual({base_url: 'angularjs/', - autobind: true}); + expect(angularJsConfig(doc)).toEqual({autobind: true}); }); it('should extract autobind config with element id from the script hashpath', function() { var doc = { getElementsByTagName: function(tagName) { expect(lowercase(tagName)).toEqual('script'); - return [{nodeName: 'SCRIPT', + return [{ + nodeName: 'SCRIPT', src: 'angularjs/angular.js#autobind=foo'}]; }}; - expect(angularJsConfig(doc)).toEqual({base_url: 'angularjs/', - autobind: 'foo'}); + expect(angularJsConfig(doc)).toEqual({autobind: 'foo'}); }); - it("should default to versioned ie-compat file if angular file is versioned", function() { + it('should default to versioned ie-compat file if angular file is versioned', function() { var doc = { getElementsByTagName: function(tagName) { expect(lowercase(tagName)).toEqual('script'); - return [{nodeName: 'SCRIPT', + return [{ + nodeName: 'SCRIPT', src: 'js/angular-0.9.0.js'}]; }}; - expect(angularJsConfig(doc)).toEqual({base_url: 'js/'}); - }); - - - it("should default to versioned ie-compat file if angular file is versioned and minified", function() { - var doc = { getElementsByTagName: function(tagName) { - expect(lowercase(tagName)).toEqual('script'); - return [{nodeName: 'SCRIPT', - src: 'js/angular-0.9.0-cba23f00.min.js'}]; - }}; - - expect(angularJsConfig(doc)).toEqual({base_url: 'js/'}); + expect(angularJsConfig(doc)).toEqual({}); }); });