diff options
| -rw-r--r-- | CHANGELOG.md | 1 | ||||
| -rw-r--r-- | src/Angular.js | 51 | ||||
| -rw-r--r-- | src/Compiler.js | 22 | ||||
| -rw-r--r-- | src/widgets.js | 8 | ||||
| -rw-r--r-- | test/AngularSpec.js | 725 | ||||
| -rw-r--r-- | test/BinderSpec.js | 110 | ||||
| -rw-r--r-- | test/CompilerSpec.js | 7 | ||||
| -rw-r--r-- | test/ResourceSpec.js | 4 | ||||
| -rw-r--r-- | test/ScenarioSpec.js | 12 | ||||
| -rw-r--r-- | test/ValidatorsSpec.js | 10 | ||||
| -rw-r--r-- | test/directivesSpec.js | 4 | ||||
| -rw-r--r-- | test/markupSpec.js | 3 | ||||
| -rw-r--r-- | test/service/invalidWidgetsSpec.js | 6 | ||||
| -rw-r--r-- | test/service/routeSpec.js | 4 | ||||
| -rw-r--r-- | test/widgetsSpec.js | 18 |
15 files changed, 524 insertions, 461 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 979d2435..04d511d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ recommended way to deal with initializing scope is to put it in the root constructor controller. To migrate simply remove the call to $init() and move any code you had before $init() to the root controller. +- Change API angular.compile(..) to angular.compile(element)([scope], [element/true]) <a name="0.9.11"><a/> diff --git a/src/Angular.js b/src/Angular.js index 9b2c7ea6..9eaeb093 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -793,21 +793,50 @@ function merge(src, dst) { * @function * * @description - * Compiles a piece of HTML or DOM into a {@link angular.scope scope} object. + * Compiles a piece of HTML string or DOM into a view and produces a linking function, which can + * then be used to link {@link angular.scope scope} and the template together. The compilation + * process walks the DOM tree and tries to match DOM elements to {@link angular.markup markup}, + * {@link angular.attrMarkup attrMarkup}, {@link angular.widget widgets}, and + * {@link angular.directive directives}. For each match it executes coresponding markup, \ + * attrMarkup, widget or directive template function and collects the instance functions into a + * single linking function which is then returned. The linking function can then be used + * many-times-over on clones of compiled DOM structure, (For example when compiling + * {@link angular.widget.@ng:repeat repeater} the resulting linking function is called once for + * each item in the collection. The `ng:repeat` does this by cloning the template DOM once for + * each item in collection and then calling the linking function to link the cloned template + * with the a new scope for each item in the collection.) + * <pre> - var scope1 = angular.compile(window.document); + var mvc1 = angular.compile(window.document)(); + mvc1.view; // compiled view elment + mvc1.scope; // scope bound to the element - var scope2 = angular.compile('<div ng:click="clicked = true">click me</div>'); + var mvc2 = angular.compile('<div ng:click="clicked = true">click me</div>')(); </pre> * - * @param {string|DOMElement} element Element to compile. - * @param {Object=} parentScope Scope to become the parent scope of the newly compiled scope. - * @returns {Object} Compiled scope object. + * @param {string|DOMElement} element Element or HTML to compile into a template function. + * @returns {function([scope][, element])} a template function which is used to bind element + * and scope. Where: + * + * * `scope` - {@link angular.scope scope} A scope to bind to. If none specified, then a new + * root scope is created. + * * `element` - {@link angular.element element} Element to use as the template. If none + * specified then reuse the element from `angular.compile(element)`. If `true` + * then clone the `angular.compile(element)`. The element must be either the same + * element as `angular.compile(element)` or an identical clone to + * `angular.compile(element)`. Using an element with differnt structure will cause + * unpredictable behavior. + * + * Calling the template function returns object: `{scope:?, view:?}`, where: + * + * * `view` - the DOM element which represents the compiled template. Either same or clone of + * `element` specifed in compile or template function. + * * `scope` - scope to which the element is bound to. Either a root scope or scope specified + * in the template function. */ -function compile(element, parentScope) { - var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget), - $element = jqLite(element); - return compiler.compile($element)($element, parentScope); +function compile(element) { + return new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget) + .compile(element); } ///////////////////////////////////////////////// @@ -989,7 +1018,7 @@ function toKeyValue(obj) { function angularInit(config){ if (config.autobind) { // TODO default to the source of angular.js - var scope = compile(window.document, _null, {'$config':config}), + var scope = compile(window.document)(null, createScope({'$config':config})), $browser = scope.$service('$browser'); if (config.css) diff --git a/src/Compiler.js b/src/Compiler.js index 6aee40b8..890f2510 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -80,30 +80,30 @@ function Compiler(markup, attrMarkup, directives, widgets){ } Compiler.prototype = { - compile: function(element) { - element = jqLite(element); + compile: function(templateElement) { + templateElement = jqLite(templateElement); var index = 0, template, - parent = element.parent(); + parent = templateElement.parent(); if (parent && parent[0]) { parent = parent[0]; for(var i = 0; i < parent.childNodes.length; i++) { - if (parent.childNodes[i] == element[0]) { + if (parent.childNodes[i] == templateElement[0]) { index = i; } } } - template = this.templatize(element, index, 0) || new Template(); - return function(element, parentScope){ - element = jqLite(element); - var scope = parentScope && parentScope.$eval - ? parentScope - : createScope(parentScope); + template = this.templatize(templateElement, index, 0) || new Template(); + return function(scope, element){ + scope = scope || createScope(); + element = element === true + ? templateElement.cloneNode() + : (jqLite(element) || templateElement); element.data($$scope, scope); template.attach(element, scope); scope.$element = element; scope.$eval(); - return scope; + return {scope:scope, view:element}; }; }, diff --git a/src/widgets.js b/src/widgets.js index 58c22081..14d6fe10 100644 --- a/src/widgets.js +++ b/src/widgets.js @@ -676,7 +676,7 @@ angularWidget('ng:include', function(element){ xhr('GET', src, function(code, response){ element.html(response); childScope = useScope || createScope(scope); - compiler.compile(element)(element, childScope); + compiler.compile(element)(childScope); scope.$eval(onloadExp); }); } else { @@ -793,7 +793,7 @@ var ngSwitch = angularWidget('ng:switch', function (element){ var caseElement = switchCase.element.cloneNode(); element.append(caseElement); childScope.$tryEval(switchCase.change, element); - switchCase.template(caseElement, childScope); + switchCase.template(childScope, caseElement); } }); }); @@ -945,7 +945,7 @@ angularWidget("@ng:repeat", function(expression, element){ (index == collectionLength - 1 ? 'last' : 'middle'); lastElement.after(cloneElement = element.cloneNode()); cloneElement.attr('ng:repeat-index', index); - linker(cloneElement, childScope); + linker(childScope, cloneElement); children.push(childScope); } childScope.$eval(); @@ -1067,7 +1067,7 @@ angularWidget('ng:view', function(element) { if (src) { $xhr('GET', src, function(code, response){ element.html(response); - compiler.compile(element)(element, childScope); + compiler.compile(element)(childScope); }); } else { element.html(''); diff --git a/test/AngularSpec.js b/test/AngularSpec.js index 010dce7c..8ff0631d 100644 --- a/test/AngularSpec.js +++ b/test/AngularSpec.js @@ -1,350 +1,389 @@ -beforeEach(function(){ - compileCache = {}; -}); - -describe('case', function(){ - it('should change case', function(){ - expect(lowercase('ABC90')).toEqual('abc90'); - expect(manualLowercase('ABC90')).toEqual('abc90'); - expect(uppercase('abc90')).toEqual('ABC90'); - expect(manualUppercase('abc90')).toEqual('ABC90'); - }); -}); - -describe("copy", function(){ - it("should return same object", function (){ - var obj = {}; - var arr = []; - expect(copy({}, obj)).toBe(obj); - expect(copy([], arr)).toBe(arr); - }); - - it("should copy Date", function(){ - var date = new Date(123); - expect(copy(date) instanceof Date).toBeTruthy(); - expect(copy(date).getTime()).toEqual(123); - expect(copy(date) === date).toBeFalsy(); - }); - - it("should copy array", function(){ - var src = [1, {name:"value"}]; - var dst = [{key:"v"}]; - expect(copy(src, dst)).toBe(dst); - expect(dst).toEqual([1, {name:"value"}]); - expect(dst[1]).toEqual({name:"value"}); - expect(dst[1]).not.toBe(src[1]); - }); - - it('should copy empty array', function() { - var src = []; - var dst = [{key: "v"}]; - expect(copy(src, dst)).toEqual([]); - expect(dst).toEqual([]); - }); - - it("should copy object", function(){ - var src = {a:{name:"value"}}; - var dst = {b:{key:"v"}}; - expect(copy(src, dst)).toBe(dst); - expect(dst).toEqual({a:{name:"value"}}); - expect(dst.a).toEqual(src.a); - expect(dst.a).not.toBe(src.a); - }); - - it("should copy primitives", function(){ - expect(copy(null)).toEqual(null); - expect(copy('')).toBe(''); - expect(copy('lala')).toBe('lala'); - expect(copy(123)).toEqual(123); - expect(copy([{key:null}])).toEqual([{key:null}]); - }); - -}); - -describe('equals', function(){ - it('should return true if same object', function(){ - var o = {}; - expect(equals(o, o)).toEqual(true); - expect(equals(1, '1')).toEqual(true); - expect(equals(1, '2')).toEqual(false); - }); - - it('should recurse into object', function(){ - expect(equals({}, {})).toEqual(true); - expect(equals({name:'misko'}, {name:'misko'})).toEqual(true); - expect(equals({name:'misko', age:1}, {name:'misko'})).toEqual(false); - expect(equals({name:'misko'}, {name:'misko', age:1})).toEqual(false); - expect(equals({name:'misko'}, {name:'adam'})).toEqual(false); - expect(equals(['misko'], ['misko'])).toEqual(true); - expect(equals(['misko'], ['adam'])).toEqual(false); - expect(equals(['misko'], ['misko', 'adam'])).toEqual(false); - }); - - it('should ignore $ member variables', function(){ - expect(equals({name:'misko', $id:1}, {name:'misko', $id:2})).toEqual(true); - expect(equals({name:'misko'}, {name:'misko', $id:2})).toEqual(true); - expect(equals({name:'misko', $id:1}, {name:'misko'})).toEqual(true); - }); - - it('should ignore functions', function(){ - expect(equals({func: function() {}}, {bar: function() {}})).toEqual(true); - }); - - it('should work well with nulls', function() { - expect(equals(null, '123')).toBe(false); - expect(equals('123', null)).toBe(false); - - var obj = {foo:'bar'}; - expect(equals(null, obj)).toBe(false); - expect(equals(obj, null)).toBe(false); - - expect(equals(null, null)).toBe(true); - }); - - it('should work well with undefined', function() { - expect(equals(undefined, '123')).toBe(false); - expect(equals('123', undefined)).toBe(false); - - var obj = {foo:'bar'}; - expect(equals(undefined, obj)).toBe(false); - expect(equals(obj, undefined)).toBe(false); - - expect(equals(undefined, undefined)).toBe(true); - }); -}); - -describe('parseKeyValue', function() { - it('should parse a string into key-value pairs', function() { - expect(parseKeyValue('')).toEqual({}); - expect(parseKeyValue('simple=pair')).toEqual({simple: 'pair'}); - expect(parseKeyValue('first=1&second=2')).toEqual({first: '1', second: '2'}); - expect(parseKeyValue('escaped%20key=escaped%20value')). +describe('angular', function(){ + describe('case', function(){ + it('should change case', function(){ + expect(lowercase('ABC90')).toEqual('abc90'); + expect(manualLowercase('ABC90')).toEqual('abc90'); + expect(uppercase('abc90')).toEqual('ABC90'); + expect(manualUppercase('abc90')).toEqual('ABC90'); + }); + }); + + describe("copy", function(){ + it("should return same object", function (){ + var obj = {}; + var arr = []; + expect(copy({}, obj)).toBe(obj); + expect(copy([], arr)).toBe(arr); + }); + + it("should copy Date", function(){ + var date = new Date(123); + expect(copy(date) instanceof Date).toBeTruthy(); + expect(copy(date).getTime()).toEqual(123); + expect(copy(date) === date).toBeFalsy(); + }); + + it("should copy array", function(){ + var src = [1, {name:"value"}]; + var dst = [{key:"v"}]; + expect(copy(src, dst)).toBe(dst); + expect(dst).toEqual([1, {name:"value"}]); + expect(dst[1]).toEqual({name:"value"}); + expect(dst[1]).not.toBe(src[1]); + }); + + it('should copy empty array', function() { + var src = []; + var dst = [{key: "v"}]; + expect(copy(src, dst)).toEqual([]); + expect(dst).toEqual([]); + }); + + it("should copy object", function(){ + var src = {a:{name:"value"}}; + var dst = {b:{key:"v"}}; + expect(copy(src, dst)).toBe(dst); + expect(dst).toEqual({a:{name:"value"}}); + expect(dst.a).toEqual(src.a); + expect(dst.a).not.toBe(src.a); + }); + + it("should copy primitives", function(){ + expect(copy(null)).toEqual(null); + expect(copy('')).toBe(''); + expect(copy('lala')).toBe('lala'); + expect(copy(123)).toEqual(123); + expect(copy([{key:null}])).toEqual([{key:null}]); + }); + + }); + + describe('equals', function(){ + it('should return true if same object', function(){ + var o = {}; + expect(equals(o, o)).toEqual(true); + expect(equals(1, '1')).toEqual(true); + expect(equals(1, '2')).toEqual(false); + }); + + it('should recurse into object', function(){ + expect(equals({}, {})).toEqual(true); + expect(equals({name:'misko'}, {name:'misko'})).toEqual(true); + expect(equals({name:'misko', age:1}, {name:'misko'})).toEqual(false); + expect(equals({name:'misko'}, {name:'misko', age:1})).toEqual(false); + expect(equals({name:'misko'}, {name:'adam'})).toEqual(false); + expect(equals(['misko'], ['misko'])).toEqual(true); + expect(equals(['misko'], ['adam'])).toEqual(false); + expect(equals(['misko'], ['misko', 'adam'])).toEqual(false); + }); + + it('should ignore $ member variables', function(){ + expect(equals({name:'misko', $id:1}, {name:'misko', $id:2})).toEqual(true); + expect(equals({name:'misko'}, {name:'misko', $id:2})).toEqual(true); + expect(equals({name:'misko', $id:1}, {name:'misko'})).toEqual(true); + }); + + it('should ignore functions', function(){ + expect(equals({func: function() {}}, {bar: function() {}})).toEqual(true); + }); + + it('should work well with nulls', function() { + expect(equals(null, '123')).toBe(false); + expect(equals('123', null)).toBe(false); + + var obj = {foo:'bar'}; + expect(equals(null, obj)).toBe(false); + expect(equals(obj, null)).toBe(false); + + expect(equals(null, null)).toBe(true); + }); + + it('should work well with undefined', function() { + expect(equals(undefined, '123')).toBe(false); + expect(equals('123', undefined)).toBe(false); + + var obj = {foo:'bar'}; + expect(equals(undefined, obj)).toBe(false); + expect(equals(obj, undefined)).toBe(false); + + expect(equals(undefined, undefined)).toBe(true); + }); + }); + + describe('parseKeyValue', function() { + it('should parse a string into key-value pairs', function() { + expect(parseKeyValue('')).toEqual({}); + expect(parseKeyValue('simple=pair')).toEqual({simple: 'pair'}); + expect(parseKeyValue('first=1&second=2')).toEqual({first: '1', second: '2'}); + expect(parseKeyValue('escaped%20key=escaped%20value')). toEqual({'escaped key': 'escaped value'}); - expect(parseKeyValue('emptyKey=')).toEqual({emptyKey: ''}); - expect(parseKeyValue('flag1&key=value&flag2')). + expect(parseKeyValue('emptyKey=')).toEqual({emptyKey: ''}); + expect(parseKeyValue('flag1&key=value&flag2')). toEqual({flag1: true, key: 'value', flag2: true}); + }); }); -}); -describe('toKeyValue', function() { - it('should parse key-value pairs into string', function() { - expect(toKeyValue({})).toEqual(''); - expect(toKeyValue({simple: 'pair'})).toEqual('simple=pair'); - expect(toKeyValue({first: '1', second: '2'})).toEqual('first=1&second=2'); - expect(toKeyValue({'escaped key': 'escaped value'})). + describe('toKeyValue', function() { + it('should parse key-value pairs into string', function() { + expect(toKeyValue({})).toEqual(''); + expect(toKeyValue({simple: 'pair'})).toEqual('simple=pair'); + expect(toKeyValue({first: '1', second: '2'})).toEqual('first=1&second=2'); + expect(toKeyValue({'escaped key': 'escaped value'})). toEqual('escaped%20key=escaped%20value'); - expect(toKeyValue({emptyKey: ''})).toEqual('emptyKey='); - }); - - it('should parse true values into flags', function() { - expect(toKeyValue({flag1: true, key: 'value', flag2: true})).toEqual('flag1&key=value&flag2'); - }); -}); - - -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 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'}]; - } - }; - - expect(angularJsConfig(doc)).toEqual({base_url: '', - ie_compat: 'angular-ie-compat.js', - ie_compat_id: 'ng-ie-compat'}); - }); - - - it('should extract angular config from the ng: attributes', function() { - var doc = { getElementsByTagName: function(tagName) { - expect(lowercase(tagName)).toEqual('script'); - return [{nodeName: 'SCRIPT', - src: 'angularjs/angular.js', - attributes: [{name: 'ng:autobind', value:undefined}, - {name: 'ng:css', value: 'css/my_custom_angular.css'}, - {name: 'ng:ie-compat', value: 'myjs/angular-ie-compat.js'}, - {name: 'ng:ie-compat-id', value: 'ngcompat'}] }]; - }}; - - expect(angularJsConfig(doc)).toEqual({base_url: 'angularjs/', - autobind: true, - css: 'css/my_custom_angular.css', - ie_compat: 'myjs/angular-ie-compat.js', - ie_compat_id: 'ngcompat'}); - }); - - - 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', - src: 'angularjs/angular.js#autobind'}]; - }}; - - expect(angularJsConfig(doc)).toEqual({base_url: 'angularjs/', - autobind: true, - ie_compat: 'angularjs/angular-ie-compat.js', - ie_compat_id: 'ng-ie-compat'}); - }); - - - 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', - src: 'js/angular-0.9.0.js'}]; - }}; - - expect(angularJsConfig(doc)).toEqual({base_url: 'js/', - ie_compat: 'js/angular-ie-compat-0.9.0.js', - ie_compat_id: 'ng-ie-compat'}); - }); - - - 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/', - ie_compat: 'js/angular-ie-compat-0.9.0-cba23f00.js', - ie_compat_id: 'ng-ie-compat'}); - }); -}); - - -describe('angular service', function() { - it('should override services', function() { - var scope = createScope(); - angular.service('fake', function() { return 'old'; }); - angular.service('fake', function() { return 'new'; }); - - expect(scope.$service('fake')).toEqual('new'); - }); - - it('should not preserve properties on override', function() { - angular.service('fake', {$one: true}, {$two: true}, {three: true}); - var result = angular.service('fake', {$four: true}); - - expect(result.$one).toBeUndefined(); - expect(result.$two).toBeUndefined(); - expect(result.three).toBeUndefined(); - expect(result.$four).toBe(true); - }); - - it('should not preserve non-angular properties on override', function() { - angular.service('fake', {one: true}, {two: true}); - var result = angular.service('fake', {third: true}); - - expect(result.one).not.toBeDefined(); - expect(result.two).not.toBeDefined(); - expect(result.third).toBeTruthy(); - }); -}); - -describe('isDate', function() { - it('should return true for Date object', function() { - expect(isDate(new Date())).toBe(true); - }); - - it('should return false for non Date objects', function() { - expect(isDate([])).toBe(false); - expect(isDate('')).toBe(false); - expect(isDate(23)).toBe(false); - expect(isDate({})).toBe(false); + expect(toKeyValue({emptyKey: ''})).toEqual('emptyKey='); + }); + + it('should parse true values into flags', function() { + expect(toKeyValue({flag1: true, key: 'value', flag2: true})).toEqual('flag1&key=value&flag2'); + }); + }); + + + 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 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'}]; + } + }; + + expect(angularJsConfig(doc)).toEqual({base_url: '', + ie_compat: 'angular-ie-compat.js', + ie_compat_id: 'ng-ie-compat'}); + }); + + + it('should extract angular config from the ng: attributes', function() { + var doc = { getElementsByTagName: function(tagName) { + expect(lowercase(tagName)).toEqual('script'); + return [{nodeName: 'SCRIPT', + src: 'angularjs/angular.js', + attributes: [{name: 'ng:autobind', value:undefined}, + {name: 'ng:css', value: 'css/my_custom_angular.css'}, + {name: 'ng:ie-compat', value: 'myjs/angular-ie-compat.js'}, + {name: 'ng:ie-compat-id', value: 'ngcompat'}] }]; + }}; + + expect(angularJsConfig(doc)).toEqual({base_url: 'angularjs/', + autobind: true, + css: 'css/my_custom_angular.css', + ie_compat: 'myjs/angular-ie-compat.js', + ie_compat_id: 'ngcompat'}); + }); + + + 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', + src: 'angularjs/angular.js#autobind'}]; + }}; + + expect(angularJsConfig(doc)).toEqual({base_url: 'angularjs/', + autobind: true, + ie_compat: 'angularjs/angular-ie-compat.js', + ie_compat_id: 'ng-ie-compat'}); + }); + + + 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', + src: 'js/angular-0.9.0.js'}]; + }}; + + expect(angularJsConfig(doc)).toEqual({base_url: 'js/', + ie_compat: 'js/angular-ie-compat-0.9.0.js', + ie_compat_id: 'ng-ie-compat'}); + }); + + + 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/', + ie_compat: 'js/angular-ie-compat-0.9.0-cba23f00.js', + ie_compat_id: 'ng-ie-compat'}); + }); + }); + + + describe('angular service', function() { + it('should override services', function() { + var scope = createScope(); + angular.service('fake', function() { return 'old'; }); + angular.service('fake', function() { return 'new'; }); + + expect(scope.$service('fake')).toEqual('new'); + }); + + it('should not preserve properties on override', function() { + angular.service('fake', {$one: true}, {$two: true}, {three: true}); + var result = angular.service('fake', {$four: true}); + + expect(result.$one).toBeUndefined(); + expect(result.$two).toBeUndefined(); + expect(result.three).toBeUndefined(); + expect(result.$four).toBe(true); + }); + + it('should not preserve non-angular properties on override', function() { + angular.service('fake', {one: true}, {two: true}); + var result = angular.service('fake', {third: true}); + + expect(result.one).not.toBeDefined(); + expect(result.two).not.toBeDefined(); + expect(result.third).toBeTruthy(); + }); + }); + + describe('isDate', function() { + it('should return true for Date object', function() { + expect(isDate(new Date())).toBe(true); + }); + + it('should return false for non Date objects', function() { + expect(isDate([])).toBe(false); + expect(isDate('')).toBe(false); + expect(isDate(23)).toBe(false); + expect(isDate({})).toBe(false); + }); + }); + + describe('compile', function(){ + var mvc; + afterEach(function(){ + dealoc(mvc.view); + }); + + it('should link to existing node and create scope', function(){ + mvc = angular.compile('<div>{{greeting = "hello world"}}</div>')(); + expect(mvc.view.text()).toEqual('hello world'); + expect(mvc.scope.greeting).toEqual('hello world'); + }); + + it('should link to existing node and given scope', function(){ + var scope = angular.scope(); + mvc = angular.compile('<div>{{greeting = "hello world"}}</div>')(scope); + expect(mvc.view.text()).toEqual('hello world'); + expect(mvc.scope).toEqual(scope); + }); + + it('should link to new node and given scope', function(){ + var scope = angular.scope(); + var template = jqLite('<div>{{greeting = "hello world"}}</div>'); + var templateFn = angular.compile(template); + var templateClone = template.cloneNode(); + mvc = templateFn(scope, templateClone); + expect(template.text()).toEqual(''); + expect(mvc.view.text()).toEqual('hello world'); + expect(mvc.view).toEqual(templateClone); + expect(mvc.scope.greeting).toEqual('hello world'); + }); + + it('should link to cloned node and create scope', function(){ + var scope = angular.scope(); + var template = jqLite('<div>{{greeting = "hello world"}}</div>'); + mvc = angular.compile(template)(scope, true); + expect(template.text()).toEqual(''); + expect(mvc.view.text()).toEqual('hello world'); + expect(mvc.scope.greeting).toEqual('hello world'); + }); }); }); diff --git a/test/BinderSpec.js b/test/BinderSpec.js index c3f90ad7..a1b9be14 100644 --- a/test/BinderSpec.js +++ b/test/BinderSpec.js @@ -4,7 +4,6 @@ describe('Binder', function(){ var self = this; this.compile = function(html, parent) { - var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget); if (self.element) dealoc(self.element); var element; if (parent) { @@ -14,11 +13,10 @@ describe('Binder', function(){ element = jqLite(html); } self.element = element; - var scope = compiler.compile(element)(element); - return {node:element, scope:scope}; + return angular.compile(element)(); }; this.compileToHtml = function (content) { - return sortedHtml(this.compile(content).node); + return sortedHtml(this.compile(content).view); }; }); @@ -92,7 +90,7 @@ describe('Binder', function(){ var form = this.compile('<div ng:bind="model.a">x</div>'); form.scope.$set('model', {a:123}); form.scope.$eval(); - assertEquals('123', form.node.text()); + assertEquals('123', form.view.text()); }); it('ReplaceBindingInTextWithSpan', function(){ @@ -115,7 +113,7 @@ describe('Binder', function(){ it('BindingOfAttributes', function(){ var c = this.compile("<a href='http://s/a{{b}}c' foo='x'></a>"); - var attrbinding = c.node.attr("ng:bind-attr"); + var attrbinding = c.view.attr("ng:bind-attr"); var bindings = fromJson(attrbinding); assertEquals("http://s/a{{b}}c", decodeURI(bindings.href)); assertTrue(!bindings.foo); @@ -123,7 +121,7 @@ describe('Binder', function(){ it('MarkMultipleAttributes', function(){ var c = this.compile('<a href="http://s/a{{b}}c" foo="{{d}}"></a>'); - var attrbinding = c.node.attr("ng:bind-attr"); + var attrbinding = c.view.attr("ng:bind-attr"); var bindings = fromJson(attrbinding); assertEquals(bindings.foo, "{{d}}"); assertEquals(decodeURI(bindings.href), "http://s/a{{b}}c"); @@ -131,23 +129,23 @@ describe('Binder', function(){ it('AttributesNoneBound', function(){ var c = this.compile("<a href='abc' foo='def'></a>"); - var a = c.node; + var a = c.view; assertEquals(a[0].nodeName, "A"); assertTrue(!a.attr("ng:bind-attr")); }); it('ExistingAttrbindingIsAppended', function(){ var c = this.compile("<a href='http://s/{{abc}}' ng:bind-attr='{\"b\":\"{{def}}\"}'></a>"); - var a = c.node; + var a = c.view; assertEquals('{"b":"{{def}}","href":"http://s/{{abc}}"}', a.attr('ng:bind-attr')); }); it('AttributesAreEvaluated', function(){ var c = this.compile('<a ng:bind-attr=\'{"a":"a", "b":"a+b={{a+b}}"}\'></a>'); - var binder = c.binder, form = c.node; + var binder = c.binder, form = c.view; c.scope.$eval('a=1;b=2'); c.scope.$eval(); - var a = c.node; + var a = c.view; assertEquals(a.attr('a'), 'a'); assertEquals(a.attr('b'), 'a+b=3'); }); @@ -158,7 +156,7 @@ describe('Binder', function(){ c.scope.$set("person.save", function(){ savedCalled = true; }); - browserTrigger(c.node, 'click'); + browserTrigger(c.view, 'click'); assertTrue(savedCalled); }); @@ -169,7 +167,7 @@ describe('Binder', function(){ log += 'click;'; }); expect(log).toEqual(''); - browserTrigger(c.node, 'click'); + browserTrigger(c.view, 'click'); expect(log).toEqual('click;'); }); @@ -179,13 +177,13 @@ describe('Binder', function(){ c.scope.$set("person.save", function(){ savedCalled = true; }); - browserTrigger(c.node, 'click'); + browserTrigger(c.view, 'click'); assertTrue(savedCalled); }); it('RepeaterUpdateBindings', function(){ var a = this.compile('<ul><LI ng:repeat="item in model.items" ng:bind="item.a"/></ul>'); - var form = a.node; + var form = a.view; var items = [{a:"A"}, {a:"B"}]; a.scope.$set('model', {items:items}); @@ -225,7 +223,7 @@ describe('Binder', function(){ assertEquals('<ul>' + '<#comment></#comment>' + '<li ng:repeat-index="0"><span ng:bind="item.a">A</span></li>' + - '</ul>', sortedHtml(a.node)); + '</ul>', sortedHtml(a.view)); }); it('ExpandEntityTag', function(){ @@ -241,11 +239,11 @@ describe('Binder', function(){ it('RepeaterAdd', function(){ var c = this.compile('<div><input type="text" name="item.x" ng:repeat="item in items"></div>'); - var doc = c.node; + var doc = c.view; c.scope.$set('items', [{x:'a'}, {x:'b'}]); c.scope.$eval(); - var first = childNode(c.node, 1); - var second = childNode(c.node, 2); + var first = childNode(c.view, 1); + var second = childNode(c.view, 2); assertEquals('a', first.val()); assertEquals('b', second.val()); @@ -261,20 +259,20 @@ describe('Binder', function(){ c.scope.$set("items", items); c.scope.$eval(); - expect(c.node[0].childNodes.length - 1).toEqual(0); + expect(c.view[0].childNodes.length - 1).toEqual(0); items.name = "misko"; c.scope.$eval(); - expect(c.node[0].childNodes.length - 1).toEqual(1); + expect(c.view[0].childNodes.length - 1).toEqual(1); delete items.name; c.scope.$eval(); - expect(c.node[0].childNodes.length - 1).toEqual(0); + expect(c.view[0].childNodes.length - 1).toEqual(0); }); it('IfTextBindingThrowsErrorDecorateTheSpan', function(){ var a = this.compile('<div>{{error.throw()}}</div>'); - var doc = a.node; + var doc = a.view; var errorLogs = a.scope.$service('$log').error.logs; a.scope.$set('error.throw', function(){throw "ErrorMsg1";}); @@ -303,7 +301,7 @@ describe('Binder', function(){ it('IfAttrBindingThrowsErrorDecorateTheAttribute', function(){ var a = this.compile('<div attr="before {{error.throw()}} after"></div>'); - var doc = a.node; + var doc = a.view; var errorLogs = a.scope.$service('$log').error.logs; a.scope.$set('error.throw', function(){throw "ErrorMsg";}); @@ -340,7 +338,7 @@ describe('Binder', function(){ '<#comment></#comment>'+ '<ul name="b1" ng:bind-attr="{"name":"{{i}}"}" ng:repeat-index="0"></ul>'+ '<ul name="b2" ng:bind-attr="{"name":"{{i}}"}" ng:repeat-index="1"></ul>'+ - '</div></div>', sortedHtml(a.node)); + '</div></div>', sortedHtml(a.view)); }); it('HideBindingExpression', function(){ @@ -349,12 +347,12 @@ describe('Binder', function(){ a.scope.$set('hidden', 3); a.scope.$eval(); - assertHidden(a.node); + assertHidden(a.view); a.scope.$set('hidden', 2); a.scope.$eval(); - assertVisible(a.node); + assertVisible(a.view); }); it('HideBinding', function(){ @@ -363,17 +361,17 @@ describe('Binder', function(){ c.scope.$set('hidden', 'true'); c.scope.$eval(); - assertHidden(c.node); + assertHidden(c.view); c.scope.$set('hidden', 'false'); c.scope.$eval(); - assertVisible(c.node); + assertVisible(c.view); c.scope.$set('hidden', ''); c.scope.$eval(); - assertVisible(c.node); + assertVisible(c.view); }); it('ShowBinding', function(){ @@ -382,17 +380,17 @@ describe('Binder', function(){ c.scope.$set('show', 'true'); c.scope.$eval(); - assertVisible(c.node); + assertVisible(c.view); c.scope.$set('show', 'false'); c.scope.$eval(); - assertHidden(c.node); + assertHidden(c.view); c.scope.$set('show', ''); c.scope.$eval(); - assertHidden(c.node); + assertHidden(c.view); }); it('BindClassUndefined', function(){ @@ -401,7 +399,7 @@ describe('Binder', function(){ assertEquals( '<div class="undefined" ng:class="undefined"></div>', - sortedHtml(doc.node)); + sortedHtml(doc.view)); }); it('BindClass', function(){ @@ -410,26 +408,26 @@ describe('Binder', function(){ c.scope.$set('class', 'testClass'); c.scope.$eval(); - assertEquals('<div class="testClass" ng:class="class"></div>', sortedHtml(c.node)); + assertEquals('<div class="testClass" ng:class="class"></div>', sortedHtml(c.view)); c.scope.$set('class', ['a', 'b']); c.scope.$eval(); - assertEquals('<div class="a b" ng:class="class"></div>', sortedHtml(c.node)); + assertEquals('<div class="a b" ng:class="class"></div>', sortedHtml(c.view)); }); it('BindClassEvenOdd', function(){ var x = this.compile('<div><div ng:repeat="i in [0,1]" ng:class-even="\'e\'" ng:class-odd="\'o\'"/></div>'); x.scope.$eval(); - var d1 = jqLite(x.node[0].childNodes[1]); - var d2 = jqLite(x.node[0].childNodes[2]); + var d1 = jqLite(x.view[0].childNodes[1]); + var d2 = jqLite(x.view[0].childNodes[2]); expect(d1.hasClass('o')).toBeTruthy(); expect(d2.hasClass('e')).toBeTruthy(); assertEquals( '<div><#comment></#comment>' + '<div class="o" ng:class-even="\'e\'" ng:class-odd="\'o\'" ng:repeat-index="0"></div>' + '<div class="e" ng:class-even="\'e\'" ng:class-odd="\'o\'" ng:repeat-index="1"></div></div>', - sortedHtml(x.node)); + sortedHtml(x.view)); }); it('BindStyle', function(){ @@ -438,7 +436,7 @@ describe('Binder', function(){ c.scope.$eval('style={color:"red"}'); c.scope.$eval(); - assertEquals("red", c.node.css('color')); + assertEquals("red", c.view.css('color')); c.scope.$eval('style={}'); c.scope.$eval(); @@ -449,7 +447,7 @@ describe('Binder', function(){ c.scope.action = function(){ throw new Error('MyError'); }; - var input = c.node; + var input = c.view; browserTrigger(input, 'click'); var error = input.attr('ng-exception'); assertTrue(!!error.match(/MyError/)); @@ -470,14 +468,14 @@ describe('Binder', function(){ "<div ng:non-bindable='true'>{{c}}</div></div>"); c.scope.$set('a', 123); c.scope.$eval(); - assertEquals('123{{a}}{{b}}{{c}}', c.node.text()); + assertEquals('123{{a}}{{b}}{{c}}', c.view.text()); }); it('OptionShouldUpdateParentToGetProperBinding', function(){ var c = this.compile('<select name="s"><option ng:repeat="i in [0,1]" value="{{i}}" ng:bind="i"></option></select>'); c.scope.$set('s', 1); c.scope.$eval(); - assertEquals(1, c.node[0].selectedIndex); + assertEquals(1, c.view[0].selectedIndex); }); it('RepeaterShouldBindInputsDefaults', function () { @@ -494,7 +492,7 @@ describe('Binder', function(){ c.scope.$set("name", "World"); c.scope.$eval(); - assertEquals('<pre ng:bind-template="Hello {{name}}!">Hello World!</pre>', sortedHtml(c.node)); + assertEquals('<pre ng:bind-template="Hello {{name}}!">Hello World!</pre>', sortedHtml(c.view)); }); it('FillInOptionValueWhenMissing', function(){ @@ -503,9 +501,9 @@ describe('Binder', function(){ c.scope.$set('a', 'A'); c.scope.$set('b', 'B'); c.scope.$eval(); - var optionA = childNode(c.node, 0); - var optionB = childNode(c.node, 1); - var optionC = childNode(c.node, 2); + var optionA = childNode(c.view, 0); + var optionB = childNode(c.view, 1); + var optionC = childNode(c.view, 2); expect(optionA.attr('value')).toEqual('A'); expect(optionA.text()).toEqual('A'); @@ -565,7 +563,7 @@ describe('Binder', function(){ '<input name="c0" ng:bind-attr="{disabled:\'{{[0]}}\'}"><input name="c1" ng:bind-attr="{disabled:\'{{[]}}\'}"></div>'); c.scope.$eval(); function assertChild(index, disabled) { - var child = childNode(c.node, index); + var child = childNode(c.view, index); assertEquals(sortedHtml(child), disabled, !!child.attr('disabled')); } @@ -581,8 +579,8 @@ describe('Binder', function(){ var c = this.compile('<div>' + '<input type="button" ng:click="greeting=\'ABC\'"/>' + '<input type="button" ng:click=":garbage:"/></div>'); - var first = jqLite(c.node[0].childNodes[0]); - var second = jqLite(c.node[0].childNodes[1]); + var first = jqLite(c.view[0].childNodes[0]); + var second = jqLite(c.view[0].childNodes[1]); var errorLogs = c.scope.$service('$log').error.logs; browserTrigger(first, 'click'); @@ -598,8 +596,8 @@ describe('Binder', function(){ var c = this.compile('<div>' + '<input type="radio" name="sex" value="female"/>' + '<input type="radio" name="sex" value="male"/></div>'); - var female = jqLite(c.node[0].childNodes[0]); - var male = jqLite(c.node[0].childNodes[1]); + var female = jqLite(c.view[0].childNodes[0]); + var male = jqLite(c.view[0].childNodes[1]); browserTrigger(female); assertEquals("female", c.scope.sex); @@ -636,7 +634,7 @@ describe('Binder', function(){ '<li ng:bind=\"k + v\" ng:repeat-index="0">a0</li>' + '<li ng:bind=\"k + v\" ng:repeat-index="1">b1</li>' + '</ul>', - sortedHtml(x.node)); + sortedHtml(x.view)); }); it('ItShouldFireChangeListenersBeforeUpdate', function(){ @@ -648,13 +646,13 @@ describe('Binder', function(){ assertEquals(123, x.scope.$get("name")); assertEquals( '<div ng:bind="name">123</div>', - sortedHtml(x.node)); + sortedHtml(x.view)); }); it('ItShouldHandleMultilineBindings', function(){ var x = this.compile('<div>{{\n 1 \n + \n 2 \n}}</div>'); x.scope.$eval(); - assertEquals("3", x.node.text()); + assertEquals("3", x.view.text()); }); it('ItBindHiddenInputFields', function(){ @@ -667,7 +665,7 @@ describe('Binder', function(){ var x = this.compile('<input name="a" ng:format="list" value="a,b">'); x.scope.$eval(); assertEquals(['a','b'], x.scope.$get('a')); - var input = x.node; + var input = x.view; input[0].value = ' x,,yz'; browserTrigger(input, 'change'); assertEquals(['x','yz'], x.scope.$get('a')); diff --git a/test/CompilerSpec.js b/test/CompilerSpec.js index 647cc366..1a93ac78 100644 --- a/test/CompilerSpec.js +++ b/test/CompilerSpec.js @@ -27,8 +27,7 @@ describe('compiler', function(){ compiler = new Compiler(markup, attrMarkup, directives, widgets); compile = function(html){ var e = jqLite("<div>" + html + "</div>"); - var scope = compiler.compile(e)(e); - return scope; + return scope = compiler.compile(e)().scope; }; }); @@ -48,7 +47,7 @@ describe('compiler', function(){ }; var template = compiler.compile(e); expect(log).toEqual("found"); - scope = template(e); + scope = template(angular.scope(), e).scope; expect(e.hasClass('ng-directive')).toEqual(true); expect(log).toEqual("found:init"); }); @@ -85,7 +84,7 @@ describe('compiler', function(){ var template = this.compile(element); return function(marker) { this.$onEval(function() { - marker.after(template(element.clone()).$element); + marker.after(template(angular.scope(), true).view); }); }; }; diff --git a/test/ResourceSpec.js b/test/ResourceSpec.js index d61282ea..adc93b92 100644 --- a/test/ResourceSpec.js +++ b/test/ResourceSpec.js @@ -169,7 +169,7 @@ describe("resource", function() { }); it('should excersize full stack', function(){ - var scope = angular.compile('<div></div>'); + var scope = angular.compile('<div></div>')().scope; var $browser = scope.$service('$browser'); var $resource = scope.$service('$resource'); var Person = $resource('/Person/:id'); @@ -181,7 +181,7 @@ describe("resource", function() { }); it('should return the same object when verifying the cache', function(){ - var scope = angular.compile('<div></div>'); + var scope = angular.compile('<div></div>')().scope; var $browser = scope.$service('$browser'); var $resource = scope.$service('$resource'); var Person = $resource('/Person/:id', null, {query: {method:'GET', isArray: true, verifyCache: true}}); diff --git a/test/ScenarioSpec.js b/test/ScenarioSpec.js index cd1e3115..ce8ce69c 100644 --- a/test/ScenarioSpec.js +++ b/test/ScenarioSpec.js @@ -12,25 +12,25 @@ describe("ScenarioSpec: Compilation", function(){ describe('compilation', function(){ it("should compile dom node and return scope", function(){ var node = jqLite('<div ng:init="a=1">{{b=a+1}}</div>')[0]; - scope = compile(node); + scope = angular.compile(node)().scope; expect(scope.a).toEqual(1); expect(scope.b).toEqual(2); }); it("should compile jQuery node and return scope", function(){ - scope = compile(jqLite('<div>{{a=123}}</div>')); + scope = compile(jqLite('<div>{{a=123}}</div>'))().scope; expect(jqLite(scope.$element).text()).toEqual('123'); }); it("should compile text node and return scope", function(){ - scope = compile('<div>{{a=123}}</div>'); + scope = angular.compile('<div>{{a=123}}</div>')().scope; expect(jqLite(scope.$element).text()).toEqual('123'); }); }); describe('scope', function(){ it("should have $set, $get, $eval, $updateView methods", function(){ - scope = compile('<div>{{a}}</div>'); + scope = angular.compile('<div>{{a}}</div>')().scope; scope.$eval("$invalidWidgets.push({})"); expect(scope.$set("a", 2)).toEqual(2); expect(scope.$get("a")).toEqual(2); @@ -40,7 +40,7 @@ describe("ScenarioSpec: Compilation", function(){ }); it("should have $ objects", function(){ - scope = compile('<div></div>', {$config: {a:"b"}}); + scope = angular.compile('<div></div>')(angular.scope({$config: {a:"b"}})).scope; expect(scope.$service('$location')).toBeDefined(); expect(scope.$get('$eval')).toBeDefined(); expect(scope.$get('$config')).toBeDefined(); @@ -51,7 +51,7 @@ describe("ScenarioSpec: Compilation", function(){ describe("configuration", function(){ it("should take location object", function(){ var url = "http://server/#?book=moby"; - scope = compile("<div>{{$location}}</div>"); + scope = angular.compile("<div>{{$location}}</div>")().scope; var $location = scope.$service('$location'); var $browser = scope.$service('$browser'); expect($location.hashSearch.book).toBeUndefined(); diff --git a/test/ValidatorsSpec.js b/test/ValidatorsSpec.js index 65b93133..2d4fca98 100644 --- a/test/ValidatorsSpec.js +++ b/test/ValidatorsSpec.js @@ -7,7 +7,7 @@ describe('ValidatorTest', function(){ validator.last = last; validator._this = this; }; - var scope = compile('<input name="name" ng:validate="myValidator:\'hevery\'"/>'); + var scope = compile('<input name="name" ng:validate="myValidator:\'hevery\'"/>')().scope; scope.name = 'misko'; scope.$eval(); assertEquals('misko', validator.first); @@ -95,7 +95,7 @@ describe('ValidatorTest', function(){ beforeEach(function(){ value = null; fn = null; - self = compile('<input />'); + self = angular.compile('<input />')().scope; jqLite(document.body).append(self.$element); self.$element.data('$validate', noop); self.$root = self; @@ -107,7 +107,8 @@ describe('ValidatorTest', function(){ it('should make a request and show spinner', function(){ var value, fn; - var scope = compile('<input type="text" name="name" ng:validate="asynchronous:asyncFn"/>'); + var scope = angular.compile( + '<input type="text" name="name" ng:validate="asynchronous:asyncFn"/>')().scope; jqLite(document.body).append(scope.$element); var input = scope.$element; scope.asyncFn = function(v,f){ @@ -149,7 +150,8 @@ describe('ValidatorTest', function(){ }); it("should handle update function", function(){ - var scope = angular.compile('<input name="name" ng:validate="asynchronous:asyncFn:updateFn"/>'); + var scope = angular.compile( + '<input name="name" ng:validate="asynchronous:asyncFn:updateFn"/>')().scope; scope.asyncFn = jasmine.createSpy(); scope.updateFn = jasmine.createSpy(); scope.name = 'misko'; diff --git a/test/directivesSpec.js b/test/directivesSpec.js index 8e5a10ee..2d4703a2 100644 --- a/test/directivesSpec.js +++ b/test/directivesSpec.js @@ -3,11 +3,9 @@ describe("directive", function(){ var compile, model, element; beforeEach(function() { - var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget); compile = function(html) { element = jqLite(html); - model = compiler.compile(element)(element); - return model; + return model = angular.compile(element)().scope; }; }); diff --git a/test/markupSpec.js b/test/markupSpec.js index 2462f19e..2c933f09 100644 --- a/test/markupSpec.js +++ b/test/markupSpec.js @@ -5,10 +5,9 @@ describe("markups", function(){ beforeEach(function() { scope = null; element = null; - var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget); compile = function(html) { element = jqLite(html); - scope = compiler.compile(element)(element); + scope = angular.compile(element)().scope; }; }); diff --git a/test/service/invalidWidgetsSpec.js b/test/service/invalidWidgetsSpec.js index b6b2da61..4a18dcf8 100644 --- a/test/service/invalidWidgetsSpec.js +++ b/test/service/invalidWidgetsSpec.js @@ -12,9 +12,9 @@ describe('$invalidWidgets', function() { it("should count number of invalid widgets", function(){ - scope = compile('<input name="price" ng:required ng:validate="number"></input>'); - jqLite(document.body).append(scope.$element); - scope.$init(); + var element = jqLite('<input name="price" ng:required ng:validate="number"></input>') + jqLite(document.body).append(element); + scope = compile(element)().scope; var $invalidWidgets = scope.$service('$invalidWidgets'); expect($invalidWidgets.length).toEqual(1); diff --git a/test/service/routeSpec.js b/test/service/routeSpec.js index 95258cc8..4dfa546c 100644 --- a/test/service/routeSpec.js +++ b/test/service/routeSpec.js @@ -18,7 +18,7 @@ describe('$route', function() { function BookChapter() { this.log = '<init>'; } - scope = compile('<div></div>').$init(); + scope = compile('<div></div>')().scope; $location = scope.$service('$location'); $route = scope.$service('$route'); $route.when('/Book/:book/Chapter/:chapter', {controller: BookChapter, template:'Chapter.html'}); @@ -87,7 +87,7 @@ describe('$route', function() { $route = scope.$service('$route'), onChangeSpy = jasmine.createSpy('onChange'); - function NotFoundCtrl() {this.notFoundProp = 'not found!'} + function NotFoundCtrl() {this.notFoundProp = 'not found!';} $route.when('/foo', {template: 'foo.html'}); $route.otherwise({template: '404.html', controller: NotFoundCtrl}); diff --git a/test/widgetsSpec.js b/test/widgetsSpec.js index 606491a9..d4d0e43a 100644 --- a/test/widgetsSpec.js +++ b/test/widgetsSpec.js @@ -4,7 +4,6 @@ describe("widget", function(){ beforeEach(function() { scope = null; element = null; - var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget); compile = function(html, parent) { if (parent) { parent.html(html); @@ -12,8 +11,7 @@ describe("widget", function(){ } else { element = jqLite(html); } - scope = compiler.compile(element)(element); - return scope; + return scope = angular.compile(element)().scope; }; }); @@ -594,7 +592,7 @@ describe("widget", function(){ }); it('should call change on switch', function(){ - var scope = angular.compile('<ng:switch on="url" change="name=\'works\'"><div ng:switch-when="a">{{name}}</div></ng:switch>'); + var scope = angular.compile('<ng:switch on="url" change="name=\'works\'"><div ng:switch-when="a">{{name}}</div></ng:switch>')().scope; scope.url = 'a'; scope.$eval(); expect(scope.name).toEqual(undefined); @@ -606,7 +604,7 @@ describe("widget", function(){ describe('ng:include', function(){ it('should include on external file', function() { var element = jqLite('<ng:include src="url" scope="childScope"></ng:include>'); - var scope = angular.compile(element); + var scope = angular.compile(element)().scope; scope.childScope = createScope(); scope.childScope.name = 'misko'; scope.url = 'myUrl'; @@ -619,7 +617,7 @@ describe("widget", function(){ it('should remove previously included text if a falsy value is bound to src', function() { var element = jqLite('<ng:include src="url" scope="childScope"></ng:include>'); - var scope = angular.compile(element); + var scope = angular.compile(element)().scope; scope.childScope = createScope(); scope.childScope.name = 'igor'; scope.url = 'myUrl'; @@ -638,7 +636,7 @@ describe("widget", function(){ it('should allow this for scope', function(){ var element = jqLite('<ng:include src="url" scope="this"></ng:include>'); - var scope = angular.compile(element); + var scope = angular.compile(element)().scope; scope.url = 'myUrl'; scope.$service('$xhr.cache').data.myUrl = {value:'{{c=c+1}}'}; scope.$eval(); @@ -652,7 +650,7 @@ describe("widget", function(){ it('should evaluate onload expression when a partial is loaded', function() { var element = jqLite('<ng:include src="url" onload="loaded = true"></ng:include>'); - var scope = angular.compile(element); + var scope = angular.compile(element)().scope; expect(scope.loaded).not.toBeDefined(); @@ -791,7 +789,7 @@ describe("widget", function(){ var rootScope, rootScope, $route, $location, $browser; beforeEach(function() { - rootScope = angular.compile('<ng:view></ng:view>'); + rootScope = angular.compile('<ng:view></ng:view>')().scope; $route = rootScope.$service('$route'); $location = rootScope.$service('$location'); $browser = rootScope.$service('$browser'); @@ -870,7 +868,7 @@ describe("widget", function(){ rootScope = angular.compile( '<div>' + 'include: <ng:include src="\'includePartial.html\'">' + - '</ng:include></div>', myApp); + '</ng:include></div>')(myApp).scope; $browser.xhr.expectGET('viewPartial.html').respond('content'); $browser.xhr.flush(); |
