diff --git a/docs/content/guide/$location.ngdoc b/docs/content/guide/$location.ngdoc index 81a7d85ad299..f7a1557a90f8 100644 --- a/docs/content/guide/$location.ngdoc +++ b/docs/content/guide/$location.ngdoc @@ -469,12 +469,12 @@ In these examples we use `` it("should show fake browser info on load", function(){ expect(addressBar.getAttribute('value')).toBe(url); - expect(element(by.binding('$location.protocol')).getText()).toBe('http'); - expect(element(by.binding('$location.host')).getText()).toBe('www.example.com'); - expect(element(by.binding('$location.port')).getText()).toBe('80'); - expect(element(by.binding('$location.path')).getText()).toBe('/path'); - expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}'); - expect(element(by.binding('$location.hash')).getText()).toBe('h'); + expect(element(by.binding('$location.protocol()')).getText()).toBe('http'); + expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com'); + expect(element(by.binding('$location.port()')).getText()).toBe('80'); + expect(element(by.binding('$location.path()')).getText()).toBe('/path'); + expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}'); + expect(element(by.binding('$location.hash()')).getText()).toBe('h'); }); @@ -485,24 +485,24 @@ In these examples we use `` expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/first?a=b"); - expect(element(by.binding('$location.protocol')).getText()).toBe('http'); - expect(element(by.binding('$location.host')).getText()).toBe('www.example.com'); - expect(element(by.binding('$location.port')).getText()).toBe('80'); - expect(element(by.binding('$location.path')).getText()).toBe('/first'); - expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}'); - expect(element(by.binding('$location.hash')).getText()).toBe(''); + expect(element(by.binding('$location.protocol()')).getText()).toBe('http'); + expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com'); + expect(element(by.binding('$location.port()')).getText()).toBe('80'); + expect(element(by.binding('$location.path()')).getText()).toBe('/first'); + expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}'); + expect(element(by.binding('$location.hash()')).getText()).toBe(''); navigation.get(1).click(); expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/sec/ond?flag#hash"); - expect(element(by.binding('$location.protocol')).getText()).toBe('http'); - expect(element(by.binding('$location.host')).getText()).toBe('www.example.com'); - expect(element(by.binding('$location.port')).getText()).toBe('80'); - expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond'); - expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}'); - expect(element(by.binding('$location.hash')).getText()).toBe('hash'); + expect(element(by.binding('$location.protocol()')).getText()).toBe('http'); + expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com'); + expect(element(by.binding('$location.port()')).getText()).toBe('80'); + expect(element(by.binding('$location.path()')).getText()).toBe('/sec/ond'); + expect(element(by.binding('$location.search()')).getText()).toBe('{"flag":true}'); + expect(element(by.binding('$location.hash()')).getText()).toBe('hash'); }); @@ -621,12 +621,12 @@ In these examples we use `` it("should show fake browser info on load", function(){ expect(addressBar.getAttribute('value')).toBe(url); - expect(element(by.binding('$location.protocol')).getText()).toBe('http'); - expect(element(by.binding('$location.host')).getText()).toBe('www.example.com'); - expect(element(by.binding('$location.port')).getText()).toBe('80'); - expect(element(by.binding('$location.path')).getText()).toBe('/path'); - expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}'); - expect(element(by.binding('$location.hash')).getText()).toBe('h'); + expect(element(by.binding('$location.protocol()')).getText()).toBe('http'); + expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com'); + expect(element(by.binding('$location.port()')).getText()).toBe('80'); + expect(element(by.binding('$location.path()')).getText()).toBe('/path'); + expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}'); + expect(element(by.binding('$location.hash()')).getText()).toBe('h'); }); @@ -637,24 +637,24 @@ In these examples we use `` expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/first?a=b"); - expect(element(by.binding('$location.protocol')).getText()).toBe('http'); - expect(element(by.binding('$location.host')).getText()).toBe('www.example.com'); - expect(element(by.binding('$location.port')).getText()).toBe('80'); - expect(element(by.binding('$location.path')).getText()).toBe('/first'); - expect(element(by.binding('$location.search')).getText()).toBe('{"a":"b"}'); - expect(element(by.binding('$location.hash')).getText()).toBe(''); + expect(element(by.binding('$location.protocol()')).getText()).toBe('http'); + expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com'); + expect(element(by.binding('$location.port()')).getText()).toBe('80'); + expect(element(by.binding('$location.path()')).getText()).toBe('/first'); + expect(element(by.binding('$location.search()')).getText()).toBe('{"a":"b"}'); + expect(element(by.binding('$location.hash()')).getText()).toBe(''); navigation.get(1).click(); expect(addressBar.getAttribute('value')).toBe("http://www.example.com/base/index.html#!/sec/ond?flag#hash"); - expect(element(by.binding('$location.protocol')).getText()).toBe('http'); - expect(element(by.binding('$location.host')).getText()).toBe('www.example.com'); - expect(element(by.binding('$location.port')).getText()).toBe('80'); - expect(element(by.binding('$location.path')).getText()).toBe('/sec/ond'); - expect(element(by.binding('$location.search')).getText()).toBe('{"flag":true}'); - expect(element(by.binding('$location.hash')).getText()).toBe('hash'); + expect(element(by.binding('$location.protocol()')).getText()).toBe('http'); + expect(element(by.binding('$location.host()')).getText()).toBe('www.example.com'); + expect(element(by.binding('$location.port()')).getText()).toBe('80'); + expect(element(by.binding('$location.path()')).getText()).toBe('/sec/ond'); + expect(element(by.binding('$location.search()')).getText()).toBe('{"flag":true}'); + expect(element(by.binding('$location.hash()')).getText()).toBe('hash'); }); diff --git a/docs/content/guide/module.ngdoc b/docs/content/guide/module.ngdoc index 5315da44ba91..1ef968347a05 100644 --- a/docs/content/guide/module.ngdoc +++ b/docs/content/guide/module.ngdoc @@ -50,7 +50,7 @@ I'm in a hurry. How do I get a Hello World module working? it('should add Hello to the name', function() { - expect(element(by.binding("{{ 'World' | greet }}")).getText()).toEqual('Hello, World!'); + expect(element(by.binding(" 'World' | greet ")).getText()).toEqual('Hello, World!'); }); @@ -128,7 +128,7 @@ The above is a suggestion. Tailor it to your needs. it('should add Hello to the name', function() { - expect(element(by.binding("{{ greeting }}")).getText()).toEqual('Bonjour World!'); + expect(element(by.binding(" greeting ")).getText()).toEqual('Bonjour World!'); }); diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index d057b17689ef..5732183e2d2e 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -253,14 +253,6 @@ "chokidar": { "version": "0.8.4", "dependencies": { - "fsevents": { - "version": "0.2.1", - "dependencies": { - "nan": { - "version": "0.8.0" - } - } - }, "recursive-readdir": { "version": "0.0.2" } @@ -492,20 +484,23 @@ } } }, + "benchmark": { + "version": "1.0.0" + }, "bower": { "version": "1.2.8", "dependencies": { "abbrev": { - "version": "1.0.4" + "version": "1.0.5" }, "archy": { "version": "0.0.2" }, "bower-config": { - "version": "0.5.0", + "version": "0.5.2", "dependencies": { "mout": { - "version": "0.6.0" + "version": "0.9.1" }, "optimist": { "version": "0.6.1", @@ -514,20 +509,20 @@ "version": "0.0.2" }, "minimist": { - "version": "0.0.8" + "version": "0.0.10" } } } } }, "bower-endpoint-parser": { - "version": "0.2.1" + "version": "0.2.2" }, "bower-json": { "version": "0.4.0", "dependencies": { "deep-extend": { - "version": "0.2.8" + "version": "0.2.11" }, "intersect": { "version": "0.0.3" @@ -556,7 +551,7 @@ "version": "0.0.2" }, "minimist": { - "version": "0.0.8" + "version": "0.0.10" } } } @@ -587,7 +582,7 @@ "version": "0.2.1", "dependencies": { "has-color": { - "version": "0.1.4" + "version": "0.1.7" }, "ansi-styles": { "version": "0.2.0" @@ -598,8 +593,11 @@ "version": "0.1.0" }, "decompress-zip": { - "version": "0.0.4", + "version": "0.0.8", "dependencies": { + "q": { + "version": "1.0.1" + }, "mkpath": { "version": "0.1.0" }, @@ -628,63 +626,83 @@ } }, "readable-stream": { - "version": "1.1.11", + "version": "1.1.13-1", "dependencies": { "core-util-is": { "version": "1.0.1" }, + "isarray": { + "version": "0.0.1" + }, "string_decoder": { "version": "0.10.25-1" }, - "debuglog": { - "version": "0.0.2" + "inherits": { + "version": "2.0.1" } } + }, + "nopt": { + "version": "2.2.1" + }, + "graceful-fs": { + "version": "3.0.2" } } }, "fstream": { - "version": "0.1.25", + "version": "0.1.31", "dependencies": { + "graceful-fs": { + "version": "3.0.2" + }, "inherits": { "version": "2.0.1" + }, + "mkdirp": { + "version": "0.5.0", + "dependencies": { + "minimist": { + "version": "0.0.8" + } + } } } }, "fstream-ignore": { - "version": "0.0.7", + "version": "0.0.10", "dependencies": { + "inherits": { + "version": "2.0.1" + }, "minimatch": { - "version": "0.2.14", + "version": "0.3.0", "dependencies": { "sigmund": { "version": "1.0.0" } } - }, - "inherits": { - "version": "2.0.1" } } }, "glob": { - "version": "3.2.9", + "version": "3.2.11", "dependencies": { + "inherits": { + "version": "2.0.1" + }, "minimatch": { - "version": "0.2.14", + "version": "0.3.0", "dependencies": { "sigmund": { "version": "1.0.0" } } - }, - "inherits": { - "version": "2.0.1" } } }, "graceful-fs": { - "version": "2.0.2" + "version": "2.0.3" }, "handlebars": { "version": "1.0.12", @@ -704,7 +722,7 @@ "version": "0.2.10" }, "source-map": { - "version": "0.1.32", + "version": "0.1.38", "dependencies": { "amdefine": { "version": "0.1.0" @@ -764,7 +782,7 @@ "version": "2.3.1" }, "open": { - "version": "0.0.4" + "version": "0.0.5" }, "osenv": { "version": "0.0.3" @@ -847,10 +865,10 @@ "version": "1.2.11" }, "form-data": { - "version": "0.1.2", + "version": "0.1.4", "dependencies": { "combined-stream": { - "version": "0.0.4", + "version": "0.0.5", "dependencies": { "delayed-stream": { "version": "0.0.5" @@ -858,7 +876,7 @@ } }, "async": { - "version": "0.2.10" + "version": "0.9.0" } } } @@ -873,10 +891,10 @@ } }, "retry": { - "version": "0.6.0" + "version": "0.6.1" }, "rimraf": { - "version": "2.2.6" + "version": "2.2.8" }, "stringify-object": { "version": "0.1.8" @@ -888,7 +906,7 @@ "version": "0.1.1", "dependencies": { "has-color": { - "version": "0.1.4" + "version": "0.1.7" }, "ansi-styles": { "version": "0.1.2" @@ -898,30 +916,44 @@ } }, "tar": { - "version": "0.1.19", + "version": "0.1.20", "dependencies": { - "inherits": { - "version": "2.0.1" - }, "block-stream": { "version": "0.0.7" + }, + "inherits": { + "version": "2.0.1" } } }, "tmp": { - "version": "0.0.23" + "version": "0.0.24" }, "update-notifier": { - "version": "0.1.7", + "version": "0.1.10", "dependencies": { + "chalk": { + "version": "0.4.0", + "dependencies": { + "has-color": { + "version": "0.1.7" + }, + "ansi-styles": { + "version": "1.0.0" + }, + "strip-ansi": { + "version": "0.1.1" + } + } + }, "configstore": { - "version": "0.1.7", + "version": "0.3.1", "dependencies": { - "lodash": { - "version": "2.4.1" + "graceful-fs": { + "version": "3.0.2" }, "js-yaml": { - "version": "2.1.3", + "version": "3.0.2", "dependencies": { "argparse": { "version": "0.1.15", @@ -938,8 +970,118 @@ "version": "1.0.4" } } + }, + "mkdirp": { + "version": "0.5.0", + "dependencies": { + "minimist": { + "version": "0.0.8" + } + } + }, + "object-assign": { + "version": "0.3.1" + }, + "osenv": { + "version": "0.1.0" + }, + "uuid": { + "version": "1.4.1" + } + } + }, + "request": { + "version": "2.40.0", + "dependencies": { + "qs": { + "version": "1.0.2" + }, + "json-stringify-safe": { + "version": "5.0.0" + }, + "mime-types": { + "version": "1.0.2" + }, + "forever-agent": { + "version": "0.5.2" + }, + "node-uuid": { + "version": "1.4.1" + }, + "tough-cookie": { + "version": "0.12.1", + "dependencies": { + "punycode": { + "version": "1.3.1" + } + } + }, + "form-data": { + "version": "0.1.4", + "dependencies": { + "combined-stream": { + "version": "0.0.5", + "dependencies": { + "delayed-stream": { + "version": "0.0.5" + } + } + }, + "mime": { + "version": "1.2.11" + }, + "async": { + "version": "0.9.0" + } + } + }, + "tunnel-agent": { + "version": "0.4.0" + }, + "http-signature": { + "version": "0.10.0", + "dependencies": { + "assert-plus": { + "version": "0.1.2" + }, + "asn1": { + "version": "0.1.11" + }, + "ctype": { + "version": "0.5.2" + } + } + }, + "oauth-sign": { + "version": "0.3.0" + }, + "hawk": { + "version": "1.1.1", + "dependencies": { + "hoek": { + "version": "0.9.1" + }, + "boom": { + "version": "0.4.2" + }, + "cryptiles": { + "version": "0.2.2" + }, + "sntp": { + "version": "0.2.4" + } + } + }, + "aws-sign2": { + "version": "0.5.0" + }, + "stringstream": { + "version": "0.0.4" } } + }, + "semver": { + "version": "2.3.2" } } }, @@ -1258,7 +1400,7 @@ "version": "0.5.0", "dependencies": { "rimraf": { - "version": "2.2.6" + "version": "2.2.8" } } }, @@ -1269,10 +1411,19 @@ "version": "0.4.10", "dependencies": { "readable-stream": { - "version": "1.0.26", + "version": "1.0.27-1", "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, "string_decoder": { "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" } } }, @@ -1285,10 +1436,19 @@ "version": "0.1.0", "dependencies": { "readable-stream": { - "version": "1.0.26", + "version": "1.0.27-1", "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, "string_decoder": { "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" } } } @@ -1341,7 +1501,12 @@ "version": "0.0.1" }, "debug": { - "version": "0.7.4" + "version": "1.0.4", + "dependencies": { + "ms": { + "version": "0.6.2" + } + } } } }, @@ -1360,7 +1525,7 @@ "version": "0.10.0", "dependencies": { "jshint": { - "version": "2.5.2", + "version": "2.5.3", "dependencies": { "shelljs": { "version": "0.3.0" @@ -1376,13 +1541,24 @@ "dependencies": { "inherits": { "version": "2.0.1" + }, + "minimatch": { + "version": "0.3.0", + "dependencies": { + "lru-cache": { + "version": "2.5.0" + }, + "sigmund": { + "version": "1.0.0" + } + } } } } } }, "minimatch": { - "version": "0.3.0", + "version": "0.4.0", "dependencies": { "lru-cache": { "version": "2.5.0" @@ -1393,7 +1569,7 @@ } }, "htmlparser2": { - "version": "3.7.2", + "version": "3.7.3", "dependencies": { "domhandler": { "version": "2.2.0" @@ -1452,7 +1628,7 @@ }, "grunt-jasmine-node": { "version": "0.1.0", - "from": "grunt-jasmine-node@git://github.com/vojtajina/grunt-jasmine-node.git#ced17cbe52c1412b2ada53160432a5b681f37cd7", + "from": "grunt-jasmine-node@git://github.com/vojtajina/grunt-jasmine-node.git#fix-grunt-exit-code", "resolved": "git://github.com/vojtajina/grunt-jasmine-node.git#ced17cbe52c1412b2ada53160432a5b681f37cd7" }, "grunt-jscs-checker": { @@ -1664,27 +1840,49 @@ "version": "0.0.2" }, "minimist": { - "version": "0.0.8" + "version": "0.0.10" } } }, "gulp-util": { - "version": "2.2.14", + "version": "2.2.20", "dependencies": { "chalk": { - "version": "0.4.0", + "version": "0.5.1", "dependencies": { - "has-color": { - "version": "0.1.4" - }, "ansi-styles": { - "version": "1.0.0" + "version": "1.1.0" + }, + "escape-string-regexp": { + "version": "1.0.1" + }, + "has-ansi": { + "version": "0.1.0", + "dependencies": { + "ansi-regex": { + "version": "0.2.1" + } + } }, "strip-ansi": { - "version": "0.1.1" + "version": "0.3.0", + "dependencies": { + "ansi-regex": { + "version": "0.2.1" + } + } + }, + "supports-color": { + "version": "0.2.0" } } }, + "dateformat": { + "version": "1.0.8-1.2.3" + }, + "lodash._reinterpolate": { + "version": "2.4.1" + }, "lodash.template": { "version": "2.4.1", "dependencies": { @@ -1752,73 +1950,104 @@ } } }, - "lodash._reinterpolate": { - "version": "2.4.1" - }, - "vinyl": { - "version": "0.2.3", + "minimist": { + "version": "0.2.0" + }, + "multipipe": { + "version": "0.1.1", "dependencies": { - "clone-stats": { - "version": "0.0.1" + "duplexer2": { + "version": "0.0.2", + "dependencies": { + "readable-stream": { + "version": "1.1.13-1", + "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, + "string_decoder": { + "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" + } + } + } + } } } }, "through2": { - "version": "0.4.1", + "version": "0.5.1", "dependencies": { "readable-stream": { - "version": "1.0.26", + "version": "1.0.27-1", "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, "string_decoder": { "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" } } }, "xtend": { - "version": "2.1.2", - "dependencies": { - "object-keys": { - "version": "0.4.0" - } - } + "version": "3.0.0" } } }, - "dateformat": { - "version": "1.0.7-1.2.3" - }, - "multipipe": { - "version": "0.0.2", + "vinyl": { + "version": "0.2.3", "dependencies": { - "duplexer2": { + "clone-stats": { "version": "0.0.1" } } - }, - "minimist": { - "version": "0.0.8" } } }, "orchestrator": { - "version": "0.3.3", + "version": "0.3.7", "dependencies": { + "end-of-stream": { + "version": "0.1.5", + "dependencies": { + "once": { + "version": "1.3.0" + } + } + }, "sequencify": { "version": "0.0.7" + }, + "stream-consume": { + "version": "0.1.0" } } }, "resolve": { - "version": "0.6.1" + "version": "0.6.3" }, "findup-sync": { - "version": "0.1.2", + "version": "0.1.3", "dependencies": { "glob": { - "version": "3.1.21", + "version": "3.2.11", "dependencies": { + "inherits": { + "version": "2.0.1" + }, "minimatch": { - "version": "0.2.14", + "version": "0.3.0", "dependencies": { "lru-cache": { "version": "2.5.0" @@ -1827,22 +2056,16 @@ "version": "1.0.0" } } - }, - "graceful-fs": { - "version": "1.2.3" - }, - "inherits": { - "version": "1.0.0" } } }, "lodash": { - "version": "1.0.1" + "version": "2.4.1" } } }, "pretty-hrtime": { - "version": "0.2.0" + "version": "0.2.1" }, "vinyl-fs": { "version": "0.0.1", @@ -1856,18 +2079,35 @@ } }, "glob-stream": { - "version": "3.1.9", + "version": "3.1.14", "dependencies": { "glob": { - "version": "3.2.9", + "version": "4.0.5", "dependencies": { "inherits": { "version": "2.0.1" + }, + "minimatch": { + "version": "1.0.0", + "dependencies": { + "lru-cache": { + "version": "2.5.0" + }, + "sigmund": { + "version": "1.0.0" + } + } + }, + "once": { + "version": "1.3.0" + }, + "graceful-fs": { + "version": "3.0.2" } } }, "minimatch": { - "version": "0.2.14", + "version": "0.3.0", "dependencies": { "lru-cache": { "version": "2.5.0" @@ -1878,24 +2118,193 @@ } }, "ordered-read-streams": { - "version": "0.0.7" + "version": "0.0.8" }, "glob2base": { - "version": "0.0.8" + "version": "0.0.9", + "dependencies": { + "lodash.findindex": { + "version": "2.4.1", + "dependencies": { + "lodash.createcallback": { + "version": "2.4.1", + "dependencies": { + "lodash._basecreatecallback": { + "version": "2.4.1", + "dependencies": { + "lodash.bind": { + "version": "2.4.1", + "dependencies": { + "lodash._createwrapper": { + "version": "2.4.1", + "dependencies": { + "lodash._basebind": { + "version": "2.4.1", + "dependencies": { + "lodash._basecreate": { + "version": "2.4.1", + "dependencies": { + "lodash._isnative": { + "version": "2.4.1" + }, + "lodash.noop": { + "version": "2.4.1" + } + } + } + } + }, + "lodash._basecreatewrapper": { + "version": "2.4.1", + "dependencies": { + "lodash._basecreate": { + "version": "2.4.1", + "dependencies": { + "lodash._isnative": { + "version": "2.4.1" + }, + "lodash.noop": { + "version": "2.4.1" + } + } + } + } + }, + "lodash.isfunction": { + "version": "2.4.1" + } + } + }, + "lodash._slice": { + "version": "2.4.1" + } + } + }, + "lodash.identity": { + "version": "2.4.1" + }, + "lodash._setbinddata": { + "version": "2.4.1", + "dependencies": { + "lodash._isnative": { + "version": "2.4.1" + }, + "lodash.noop": { + "version": "2.4.1" + } + } + }, + "lodash.support": { + "version": "2.4.1", + "dependencies": { + "lodash._isnative": { + "version": "2.4.1" + } + } + } + } + }, + "lodash._baseisequal": { + "version": "2.4.1", + "dependencies": { + "lodash.forin": { + "version": "2.4.1" + }, + "lodash._getarray": { + "version": "2.4.1", + "dependencies": { + "lodash._arraypool": { + "version": "2.4.1" + } + } + }, + "lodash.isfunction": { + "version": "2.4.1" + }, + "lodash._objecttypes": { + "version": "2.4.1" + }, + "lodash._releasearray": { + "version": "2.4.1", + "dependencies": { + "lodash._arraypool": { + "version": "2.4.1" + }, + "lodash._maxpoolsize": { + "version": "2.4.1" + } + } + } + } + }, + "lodash.isobject": { + "version": "2.4.1", + "dependencies": { + "lodash._objecttypes": { + "version": "2.4.1" + } + } + }, + "lodash.keys": { + "version": "2.4.1", + "dependencies": { + "lodash._isnative": { + "version": "2.4.1" + }, + "lodash._shimkeys": { + "version": "2.4.1", + "dependencies": { + "lodash._objecttypes": { + "version": "2.4.1" + } + } + } + } + }, + "lodash.property": { + "version": "2.4.1" + } + } + } + } + } + } }, "unique-stream": { - "version": "0.0.3" + "version": "1.0.0" }, - "through": { - "version": "2.3.4" + "through2": { + "version": "0.5.1", + "dependencies": { + "readable-stream": { + "version": "1.0.27-1", + "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, + "string_decoder": { + "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" + } + } + }, + "xtend": { + "version": "3.0.0" + } + } } } }, "glob-watcher": { - "version": "0.0.3", + "version": "0.0.6", "dependencies": { "gaze": { - "version": "0.4.3", + "version": "0.5.1", "dependencies": { "globule": { "version": "0.1.0", @@ -1935,7 +2344,7 @@ "version": "0.3.5" }, "graceful-fs": { - "version": "2.0.2" + "version": "2.0.3" }, "map-stream": { "version": "0.1.0" @@ -1957,22 +2366,44 @@ "version": "2.3.4" }, "gulp-util": { - "version": "2.2.14", + "version": "2.2.20", "dependencies": { "chalk": { - "version": "0.4.0", + "version": "0.5.1", "dependencies": { - "has-color": { - "version": "0.1.4" - }, "ansi-styles": { - "version": "1.0.0" + "version": "1.1.0" + }, + "escape-string-regexp": { + "version": "1.0.1" + }, + "has-ansi": { + "version": "0.1.0", + "dependencies": { + "ansi-regex": { + "version": "0.2.1" + } + } }, "strip-ansi": { - "version": "0.1.1" + "version": "0.3.0", + "dependencies": { + "ansi-regex": { + "version": "0.2.1" + } + } + }, + "supports-color": { + "version": "0.2.0" } } }, + "dateformat": { + "version": "1.0.8-1.2.3" + }, + "lodash._reinterpolate": { + "version": "2.4.1" + }, "lodash.template": { "version": "2.4.1", "dependencies": { @@ -2040,51 +2471,68 @@ } } }, - "lodash._reinterpolate": { - "version": "2.4.1" + "minimist": { + "version": "0.2.0" }, - "vinyl": { - "version": "0.2.3", + "multipipe": { + "version": "0.1.1", "dependencies": { - "clone-stats": { - "version": "0.0.1" + "duplexer2": { + "version": "0.0.2", + "dependencies": { + "readable-stream": { + "version": "1.1.13-1", + "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, + "string_decoder": { + "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" + } + } + } + } } } }, "through2": { - "version": "0.4.1", + "version": "0.5.1", "dependencies": { "readable-stream": { - "version": "1.0.26", + "version": "1.0.27-1", "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, "string_decoder": { "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" } } }, "xtend": { - "version": "2.1.2", - "dependencies": { - "object-keys": { - "version": "0.4.0" - } - } + "version": "3.0.0" } } }, - "dateformat": { - "version": "1.0.7-1.2.3" - }, - "multipipe": { - "version": "0.0.2", + "vinyl": { + "version": "0.2.3", "dependencies": { - "duplexer2": { + "clone-stats": { "version": "0.0.1" } } - }, - "minimist": { - "version": "0.0.8" } } } @@ -2109,17 +2557,34 @@ "version": "0.4.5", "dependencies": { "glob": { - "version": "3.2.9", + "version": "4.0.5", "dependencies": { "inherits": { "version": "2.0.1" + }, + "minimatch": { + "version": "1.0.0", + "dependencies": { + "lru-cache": { + "version": "2.5.0" + }, + "sigmund": { + "version": "1.0.0" + } + } + }, + "once": { + "version": "1.3.0" + }, + "graceful-fs": { + "version": "3.0.2" } } } } }, "minimatch": { - "version": "0.2.14", + "version": "0.4.0", "dependencies": { "lru-cache": { "version": "2.5.0" @@ -2142,10 +2607,19 @@ "version": "1.1.1" }, "readable-stream": { - "version": "1.0.26", + "version": "1.0.27-1", "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, "string_decoder": { "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" } } } @@ -2160,22 +2634,44 @@ } }, "gulp-util": { - "version": "2.2.14", + "version": "2.2.20", "dependencies": { "chalk": { - "version": "0.4.0", + "version": "0.5.1", "dependencies": { - "has-color": { - "version": "0.1.4" - }, "ansi-styles": { - "version": "1.0.0" + "version": "1.1.0" + }, + "escape-string-regexp": { + "version": "1.0.1" + }, + "has-ansi": { + "version": "0.1.0", + "dependencies": { + "ansi-regex": { + "version": "0.2.1" + } + } }, "strip-ansi": { - "version": "0.1.1" + "version": "0.3.0", + "dependencies": { + "ansi-regex": { + "version": "0.2.1" + } + } + }, + "supports-color": { + "version": "0.2.0" } } }, + "dateformat": { + "version": "1.0.8-1.2.3" + }, + "lodash._reinterpolate": { + "version": "2.4.1" + }, "lodash.template": { "version": "2.4.1", "dependencies": { @@ -2243,51 +2739,68 @@ } } }, - "lodash._reinterpolate": { - "version": "2.4.1" + "minimist": { + "version": "0.2.0" }, - "vinyl": { - "version": "0.2.3", + "multipipe": { + "version": "0.1.1", "dependencies": { - "clone-stats": { - "version": "0.0.1" + "duplexer2": { + "version": "0.0.2", + "dependencies": { + "readable-stream": { + "version": "1.1.13-1", + "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, + "string_decoder": { + "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" + } + } + } + } } } }, "through2": { - "version": "0.4.1", + "version": "0.5.1", "dependencies": { "readable-stream": { - "version": "1.0.26", + "version": "1.0.27-1", "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, "string_decoder": { "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" } } }, "xtend": { - "version": "2.1.2", - "dependencies": { - "object-keys": { - "version": "0.4.0" - } - } + "version": "3.0.0" } } }, - "dateformat": { - "version": "1.0.7-1.2.3" - }, - "multipipe": { - "version": "0.0.2", + "vinyl": { + "version": "0.2.3", "dependencies": { - "duplexer2": { + "clone-stats": { "version": "0.0.1" } } - }, - "minimist": { - "version": "0.0.8" } } }, @@ -2480,7 +2993,7 @@ "version": "1.7.1" }, "jasmine-growl-reporter": { - "version": "0.0.2", + "version": "0.0.3", "dependencies": { "growl": { "version": "1.7.0" @@ -2488,7 +3001,7 @@ } }, "requirejs": { - "version": "2.1.11" + "version": "2.1.14" }, "walkdir": { "version": "0.0.7" @@ -2514,10 +3027,21 @@ "version": "0.1.5", "dependencies": { "glob": { - "version": "3.2.9", + "version": "3.2.11", "dependencies": { "inherits": { "version": "2.0.1" + }, + "minimatch": { + "version": "0.3.0", + "dependencies": { + "lru-cache": { + "version": "2.5.0" + }, + "sigmund": { + "version": "1.0.0" + } + } } } } @@ -2540,7 +3064,7 @@ "version": "0.4.0", "dependencies": { "has-color": { - "version": "0.1.4" + "version": "0.1.7" }, "ansi-styles": { "version": "1.0.0" @@ -2861,19 +3385,132 @@ "version": "0.2.0", "dependencies": { "wd": { - "version": "0.2.10", + "version": "0.2.27", "dependencies": { + "archiver": { + "version": "0.10.1", + "dependencies": { + "buffer-crc32": { + "version": "0.2.3" + }, + "readable-stream": { + "version": "1.0.27-1", + "dependencies": { + "core-util-is": { + "version": "1.0.1" + }, + "isarray": { + "version": "0.0.1" + }, + "string_decoder": { + "version": "0.10.25-1" + }, + "inherits": { + "version": "2.0.1" + } + } + }, + "tar-stream": { + "version": "0.4.4", + "dependencies": { + "bl": { + "version": "0.8.2" + }, + "end-of-stream": { + "version": "0.1.5", + "dependencies": { + "once": { + "version": "1.3.0" + } + } + }, + "xtend": { + "version": "3.0.0" + } + } + }, + "zip-stream": { + "version": "0.3.7", + "dependencies": { + "crc32-stream": { + "version": "0.2.0" + }, + "debug": { + "version": "1.0.4", + "dependencies": { + "ms": { + "version": "0.6.2" + } + } + }, + "deflate-crc32-stream": { + "version": "0.1.1" + } + } + }, + "lazystream": { + "version": "0.1.0" + }, + "file-utils": { + "version": "0.2.0", + "dependencies": { + "iconv-lite": { + "version": "0.2.11" + }, + "rimraf": { + "version": "2.2.8" + }, + "glob": { + "version": "3.2.11", + "dependencies": { + "inherits": { + "version": "2.0.1" + }, + "minimatch": { + "version": "0.3.0", + "dependencies": { + "lru-cache": { + "version": "2.5.0" + }, + "sigmund": { + "version": "1.0.0" + } + } + } + } + }, + "minimatch": { + "version": "0.2.14", + "dependencies": { + "lru-cache": { + "version": "2.5.0" + }, + "sigmund": { + "version": "1.0.0" + } + } + }, + "findup-sync": { + "version": "0.1.3" + }, + "isbinaryfile": { + "version": "2.0.1" + } + } + } + } + }, "async": { - "version": "0.2.10" + "version": "0.9.0" }, - "vargs": { - "version": "0.1.0" + "lodash": { + "version": "2.4.1" }, "q": { - "version": "1.0.0" + "version": "1.0.1" }, "request": { - "version": "2.33.0", + "version": "2.36.0", "dependencies": { "qs": { "version": "0.6.6" @@ -2881,28 +3518,28 @@ "json-stringify-safe": { "version": "5.0.0" }, + "mime": { + "version": "1.2.11" + }, "forever-agent": { "version": "0.5.2" }, "node-uuid": { "version": "1.4.1" }, - "mime": { - "version": "1.2.11" - }, "tough-cookie": { "version": "0.12.1", "dependencies": { "punycode": { - "version": "1.2.4" + "version": "1.3.1" } } }, "form-data": { - "version": "0.1.2", + "version": "0.1.4", "dependencies": { "combined-stream": { - "version": "0.0.4", + "version": "0.0.5", "dependencies": { "delayed-stream": { "version": "0.0.5" @@ -2912,7 +3549,7 @@ } }, "tunnel-agent": { - "version": "0.3.0" + "version": "0.4.0" }, "http-signature": { "version": "0.10.0", @@ -2953,109 +3590,11 @@ } } }, - "archiver": { - "version": "0.5.2", - "dependencies": { - "readable-stream": { - "version": "1.0.26", - "dependencies": { - "string_decoder": { - "version": "0.10.25-1" - } - } - }, - "zip-stream": { - "version": "0.1.4", - "dependencies": { - "lodash.defaults": { - "version": "2.4.1", - "dependencies": { - "lodash.keys": { - "version": "2.4.1", - "dependencies": { - "lodash._isnative": { - "version": "2.4.1" - }, - "lodash.isobject": { - "version": "2.4.1" - }, - "lodash._shimkeys": { - "version": "2.4.1" - } - } - }, - "lodash._objecttypes": { - "version": "2.4.1" - } - } - } - } - }, - "lazystream": { - "version": "0.1.0" - }, - "file-utils": { - "version": "0.1.5", - "dependencies": { - "lodash": { - "version": "2.1.0" - }, - "iconv-lite": { - "version": "0.2.11" - }, - "rimraf": { - "version": "2.2.6" - }, - "glob": { - "version": "3.2.9", - "dependencies": { - "inherits": { - "version": "2.0.1" - } - } - }, - "minimatch": { - "version": "0.2.14", - "dependencies": { - "lru-cache": { - "version": "2.5.0" - }, - "sigmund": { - "version": "1.0.0" - } - } - }, - "findup-sync": { - "version": "0.1.2", - "dependencies": { - "glob": { - "version": "3.1.21", - "dependencies": { - "graceful-fs": { - "version": "1.2.3" - }, - "inherits": { - "version": "1.0.0" - } - } - }, - "lodash": { - "version": "1.0.1" - } - } - }, - "isbinaryfile": { - "version": "0.1.9" - } - } - } - } - }, - "lodash": { - "version": "2.4.1" - }, "underscore.string": { "version": "2.3.3" + }, + "vargs": { + "version": "0.1.0" } } }, @@ -3156,39 +3695,44 @@ "version": "0.0.2" }, "promises-aplus-tests": { - "version": "2.0.4", + "version": "2.0.5", "dependencies": { "mocha": { - "version": "1.11.0", + "version": "1.21.4", "dependencies": { "commander": { - "version": "0.6.1" + "version": "2.0.0" }, "growl": { - "version": "1.7.0" + "version": "1.8.1" }, "jade": { "version": "0.26.3", "dependencies": { + "commander": { + "version": "0.6.1" + }, "mkdirp": { "version": "0.3.0" } } }, "diff": { - "version": "1.0.2" + "version": "1.0.7" }, "debug": { - "version": "0.7.4" + "version": "1.0.4", + "dependencies": { + "ms": { + "version": "0.6.2" + } + } }, "mkdirp": { "version": "0.3.5" }, - "ms": { - "version": "0.3.0" - }, "glob": { - "version": "3.2.1", + "version": "3.2.3", "dependencies": { "minimatch": { "version": "0.2.14", @@ -3202,35 +3746,43 @@ } }, "graceful-fs": { - "version": "1.2.3" + "version": "2.0.3" }, "inherits": { - "version": "1.0.0" + "version": "2.0.1" } } } } }, "sinon": { - "version": "1.7.3", + "version": "1.10.3", "dependencies": { - "buster-format": { - "version": "0.5.6", + "formatio": { + "version": "1.0.2", + "dependencies": { + "samsam": { + "version": "1.1.1" + } + } + }, + "util": { + "version": "0.10.3", "dependencies": { - "buster-core": { - "version": "0.6.4" + "inherits": { + "version": "2.0.1" } } } } }, "underscore": { - "version": "1.4.4" + "version": "1.6.0" } } }, "protractor": { - "version": "1.0.0", + "version": "1.1.1", "dependencies": { "request": { "version": "2.36.0", @@ -3254,7 +3806,7 @@ "version": "0.12.1", "dependencies": { "punycode": { - "version": "1.3.0" + "version": "1.3.1" } } }, diff --git a/package.json b/package.json index e86ec044616d..49938bc0b2d4 100644 --- a/package.json +++ b/package.json @@ -6,11 +6,19 @@ "url": "https://github.com/angular/angular.js.git" }, "devDependencies": { + "angular-benchpress": "0.x.x", + "benchmark": "^1.0.0", + "bower": "~1.2.2", + "browserstacktunnel-wrapper": "~1.1.1", + "canonical-path": "0.0.2", + "dgeni": "^0.3.0", + "dgeni-packages": "^0.9.7", + "event-stream": "~3.1.0", "grunt": "~0.4.2", "grunt-bump": "~0.0.13", "grunt-contrib-clean": "~0.5.0", - "grunt-contrib-connect": "~0.5.0", "grunt-contrib-compress": "~0.5.2", + "grunt-contrib-connect": "~0.5.0", "grunt-contrib-copy": "~0.4.1", "grunt-contrib-jshint": "~0.10.0", "grunt-ddescribe-iit": "~0.0.1", @@ -19,42 +27,35 @@ "grunt-merge-conflict": "~0.0.1", "grunt-parallel": "~0.3.1", "grunt-shell": "~0.4.0", - "load-grunt-tasks": "~0.3.0", - "bower": "~1.2.2", + "gulp": "~3.4.0", + "gulp-concat": "~2.1.7", + "gulp-jshint": "~1.4.2", "jasmine-node": "~1.11.0", - "q": "~1.0.0", - "shelljs": "~0.2.6", + "jasmine-reporters": "~0.2.1", + "jshint-stylish": "~0.1.5", "karma": "^0.12.0", - "karma-jasmine": "0.1.5", + "karma-browserstack-launcher": "0.0.7", "karma-chrome-launcher": "0.1.2", "karma-firefox-launcher": "0.1.3", - "karma-ng-scenario": "0.1.0", + "karma-jasmine": "0.1.5", "karma-junit-reporter": "0.2.1", + "karma-ng-scenario": "0.1.0", "karma-sauce-launcher": "0.2.0", "karma-script-launcher": "0.1.0", - "karma-browserstack-launcher": "0.0.7", - "protractor": "1.0.0", - "yaml-js": "~0.0.8", - "rewire": "1.1.3", - "promises-aplus-tests": "~2.0.4", - "semver": "~2.1.0", + "load-grunt-tasks": "~0.3.0", "lodash": "~2.1.0", - "browserstacktunnel-wrapper": "~1.1.1", - "jasmine-reporters": "~0.2.1", - "gulp": "~3.4.0", - "event-stream": "~3.1.0", "marked": "~0.3.0", - "gulp-concat": "~2.1.7", - "canonical-path": "0.0.2", - "winston": "~0.7.2", - "dgeni": "^0.3.0", - "dgeni-packages": "^0.9.7", - "gulp-jshint": "~1.4.2", - "jshint-stylish": "~0.1.5", "node-html-encoder": "0.0.2", - "sorted-object": "^1.0.0", + "promises-aplus-tests": "~2.0.4", + "protractor": "^1.1.1", + "q": "~1.0.0", "qq": "^0.3.5", - "angular-benchpress": "0.x.x" + "rewire": "1.1.3", + "semver": "~2.1.0", + "shelljs": "~0.2.6", + "sorted-object": "^1.0.0", + "winston": "~0.7.2", + "yaml-js": "~0.0.8" }, "licenses": [ { diff --git a/protractor-shared-conf.js b/protractor-shared-conf.js index d2ac3ced7bd8..039d8ce973c8 100644 --- a/protractor-shared-conf.js +++ b/protractor-shared-conf.js @@ -19,6 +19,13 @@ exports.config = { browser.addMockModule('disableNgAnimate', disableNgAnimate); + browser.addMockModule('enable-binding-info', function() { + angular.module('enable-binding-info', []) + .config(['$compileProvider', function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }]); + }); + // Store the name of the browser that's currently being used. browser.getCapabilities().then(function(caps) { browser.params.browser = caps.get('browserName'); diff --git a/scripts/clean-shrinkwrap.js b/scripts/clean-shrinkwrap.js index 66326f4f2fca..c46fe295da6b 100755 --- a/scripts/clean-shrinkwrap.js +++ b/scripts/clean-shrinkwrap.js @@ -23,9 +23,6 @@ function cleanModule(module, name) { if (name === 'chokidar') { if (module.version === '0.8.1') { delete module.dependencies; - } else if ( module.version !== '0.8.2') { - throw new Error("Unfamiliar chokidar version (v" + module.version + - ") , please check status of https://github.com/paulmillr/chokidar/pull/106"); } } diff --git a/src/.jshintrc b/src/.jshintrc index 87dd0638cf94..6b7190b12ff8 100644 --- a/src/.jshintrc +++ b/src/.jshintrc @@ -88,6 +88,7 @@ "getBlockNodes": false, "createMap": false, "VALIDITY_STATE_PROPERTY": false, + "reloadWithDebugInfo": false, "skipDestroyOnNextJQueryCleanData": true, diff --git a/src/Angular.js b/src/Angular.js index 6b7bd00c28a7..614fec2756d6 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -1414,6 +1414,13 @@ function bootstrap(element, modules, config) { modules.unshift(['$provide', function($provide) { $provide.value('$rootElement', element); }]); + + if ( config.enableDebugInfo ) { + modules.unshift(['$compileProvider', function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }]); + } + modules.unshift('ng'); var injector = createInjector(modules, config.strictDi); injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', @@ -1427,8 +1434,14 @@ function bootstrap(element, modules, config) { return injector; }; + var NG_ENABLE_DEBUG_INFO = /^NG_ENABLE_DEBUG_INFO!/; var NG_DEFER_BOOTSTRAP = /^NG_DEFER_BOOTSTRAP!/; + if (window && NG_ENABLE_DEBUG_INFO.test(window.name)) { + config.enableDebugInfo = true; + window.name = window.name.replace(NG_ENABLE_DEBUG_INFO, ''); + } + if (window && !NG_DEFER_BOOTSTRAP.test(window.name)) { return doBootstrap(); } @@ -1442,6 +1455,48 @@ function bootstrap(element, modules, config) { }; } +/** + * @ngdoc function + * @name angular.reloadWithDebugInfo + * @module ng + * @description + * Use this function to reload the current application with debug information turned on. + * + * To significantly improve performance various debugging information is no longer added to + * the DOM by the compiler. The information that is not included is: + * + * * As a result of `ngBind`, `ngBindHtml` or `{{...}}` interpolations, binding data and CSS class + * `ng-class` is attached to the corresponding element. + * + * * Where the compiler has created a new scope, the scope and either `ng-scope` or `ng-isolated-scope` + * CSS class are attached to the corresponding element. These scope references can then be accessed via + * `element.scope()` and `element.isolateScope()`. + * + * If you wish to debug an application via this information then you should open up a debug + * console in the browser then call this method directly in this console: + * + * ```js + * angular.reloadWithDebugInfo(); + * ``` + * + * The page should reload and the debug information should now be available. + * + * If you want to include this debug information in your application all the time then you + * can turn it on in a configuration block. + * + * ```js + * appModule.config(['$compileProvider', function($compileProvider) { + * $compileProvider.enableDebugInfo(true); + * }]); + * ``` + * + * See {@link $compileProvider}. + */ +function reloadWithDebugInfo(doReload) { + window.name = 'NG_ENABLE_DEBUG_INFO!' + window.name; + if ( doReload !== false ) window.location.reload(); +} + var SNAKE_CASE_REGEXP = /[A-Z]/g; function snake_case(name, separator) { separator = separator || '_'; diff --git a/src/AngularPublic.js b/src/AngularPublic.js index e859a0da7577..a0a61b727b39 100644 --- a/src/AngularPublic.js +++ b/src/AngularPublic.js @@ -136,7 +136,8 @@ function publishExternalAPI(angular){ 'uppercase': uppercase, 'callbacks': {counter: 0}, '$$minErr': minErr, - '$$csp': csp + '$$csp': csp, + 'reloadWithDebugInfo': reloadWithDebugInfo }); angularModule = setupModuleLoader(window); diff --git a/src/ng/compile.js b/src/ng/compile.js index 18cb173fa035..a86938662bb4 100644 --- a/src/ng/compile.js +++ b/src/ng/compile.js @@ -668,6 +668,33 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } }; + /** + * @ngdoc method + * @name $compileProvider#enableDebugInfo + * + * @param {boolean=} enabled update the enableDebugInfo state if provided, otherwise just return the + * current enabled state + * @returns {*} current value if used as getter or itself (chaining) if used as setter + * + * @kind function + * + * @description + * Call this method to enable various debug runtime information in the compiler such as adding + * binding information and a reference to the current scope on to DOM elements. + * If enabled, the compiler will add the following to DOM elements that have been bound to the scope + * * `ng-binding` CSS class + * * `$binding` data object containing the value of the binding (or an array if there are multiple + * bindings) + */ + var enableDebugInfo = false; + this.enableDebugInfo = function(enabled) { + if(isDefined(enabled)) { + enableDebugInfo = enabled; + return this; + } + return enableDebugInfo; + }; + this.$get = [ '$injector', '$interpolate', '$exceptionHandler', '$http', '$templateCache', '$parse', '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri', @@ -859,6 +886,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } }; + + function safeAddClass($element, className) { + try { + $element.addClass(className); + } catch(e) { + // ignore, since it means that we are trying to set class on + // SVG element, where class name is read-only. + } + } + + var startSymbol = $interpolate.startSymbol(), endSymbol = $interpolate.endSymbol(), denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}') @@ -869,6 +907,17 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { NG_ATTR_BINDING = /^ngAttr[A-Z]/; + compile.$$addBindingInfo = enableDebugInfo ? function $$addBindingInfo(element, binding) { + safeAddClass(element, 'ng-binding'); + element.data('$binding', (element.data('$binding') || []).concat(binding.expressions || [binding])); + } : noop; + + compile.$$addScopeInfo = enableDebugInfo ? function $$addScopeInfo(element, scope, isolated, noTemplate) { + safeAddClass(jqLite(element), isolated ? 'ng-isolate-scope' : 'ng-scope'); + var dataName = isolated ? (noTemplate ? '$isolateScopeNoTemplate' : '$isolateScope') : '$scope'; + element.data ? element.data(dataName, scope) : jqLite.data(element, dataName, scope); + } : noop; + return compile; //================================ @@ -890,9 +939,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { var compositeLinkFn = compileNodes($compileNodes, transcludeFn, $compileNodes, maxPriority, ignoreDirective, previousCompileContext); - safeAddClass($compileNodes, 'ng-scope'); - var namespace = null; + return function publicLinkFn(scope, cloneConnectFn, transcludeControllers, parentBoundTranscludeFn, futureParentElement){ + var namespace = null; assertArg(scope, 'scope'); if (!namespace) { namespace = detectNamespaceForChildElements(futureParentElement); @@ -915,7 +964,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } } - $linkNode.data('$scope', scope); + compile.$$addScopeInfo($linkNode, scope); if (cloneConnectFn) cloneConnectFn($linkNode, scope); if (compositeLinkFn) compositeLinkFn(scope, $linkNode, $linkNode, parentBoundTranscludeFn); @@ -933,15 +982,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { } } - function safeAddClass($element, className) { - try { - $element.addClass(className); - } catch(e) { - // ignore, since it means that we are trying to set class on - // SVG element, where class name is read-only. - } - } - /** * Compile function matches each node in nodeList against the directives. Once all directives * for a particular node are collected their compile functions are executed. The compile @@ -974,10 +1014,6 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { null, [], [], previousCompileContext) : null; - if (nodeLinkFn && nodeLinkFn.scope) { - safeAddClass(attrs.$$element, 'ng-scope'); - } - childLinkFn = (nodeLinkFn && nodeLinkFn.terminal || !(childNodes = nodeList[i].childNodes) || !childNodes.length) @@ -1025,7 +1061,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { if (nodeLinkFn) { if (nodeLinkFn.scope) { childScope = scope.$new(); - jqLite.data(node, '$scope', childScope); + compile.$$addScopeInfo(node, childScope); } else { childScope = scope; } @@ -1526,14 +1562,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { isolateScope = scope.$new(true); - if (templateDirective && (templateDirective === newIsolateScopeDirective || - templateDirective === newIsolateScopeDirective.$$originalDirective)) { - $element.data('$isolateScope', isolateScope); - } else { - $element.data('$isolateScopeNoTemplate', isolateScope); - } - - + compile.$$addScopeInfo($element, isolateScope, true, !(templateDirective && (templateDirective === newIsolateScopeDirective || + templateDirective === newIsolateScopeDirective.$$originalDirective))); safeAddClass($element, 'ng-isolate-scope'); @@ -1948,17 +1978,9 @@ function $CompileProvider($provide, $$sanitizeUriProvider) { directives.push({ priority: 0, compile: function textInterpolateCompileFn(templateNode) { - // when transcluding a template that has bindings in the root - // then we don't have a parent and should do this in the linkFn - var parent = templateNode.parent(), hasCompileParent = parent.length; - if (hasCompileParent) safeAddClass(templateNode.parent(), 'ng-binding'); - return function textInterpolateLinkFn(scope, node) { - var parent = node.parent(), - bindings = parent.data('$binding') || []; - bindings.push(interpolateFn); - parent.data('$binding', bindings); - if (!hasCompileParent) safeAddClass(parent, 'ng-binding'); + var parent = node.parent(); + compile.$$addBindingInfo(parent, interpolateFn, true); scope.$watch(interpolateFn, function interpolateFnWatchAction(value) { node[0].nodeValue = value; }); diff --git a/src/ng/directive/input.js b/src/ng/directive/input.js index c2cf92332081..051f15c021d2 100644 --- a/src/ng/directive/input.js +++ b/src/ng/directive/input.js @@ -798,7 +798,7 @@ var inputType = { it('should change state', function() { - var color = element(by.binding('color')); + var color = element(by.binding('color | json')); expect(color.getText()).toContain('blue'); @@ -1334,7 +1334,7 @@ function checkboxInputType(scope, element, attr, ctrl, $sniffer, $browser, $filt - var user = element(by.binding('{{user}}')); + var user = element(by.binding('user')); var userNameValid = element(by.binding('myForm.userName.$valid')); var lastNameValid = element(by.binding('myForm.lastName.$valid')); var lastNameError = element(by.binding('myForm.lastName.$error')); @@ -2414,7 +2414,7 @@ var minlengthDirective = function() { * * * var listInput = element(by.model('names')); - * var names = element(by.binding('{{names}}')); + * var names = element(by.binding('names')); * var valid = element(by.binding('myForm.namesInput.$valid')); * var error = element(by.css('span.error')); * @@ -2444,7 +2444,7 @@ var minlengthDirective = function() { * * it("should split the text by newlines", function() { * var listInput = element(by.model('list')); - * var output = element(by.binding('{{ list | json }}')); + * var output = element(by.binding(' list | json ')); * listInput.sendKeys('abc\ndef\nghi'); * expect(output.getText()).toContain('[\n "abc",\n "def",\n "ghi"\n]'); * }); diff --git a/src/ng/directive/ngBind.js b/src/ng/directive/ngBind.js index d4dd81fc9121..6be2dfd05fd2 100644 --- a/src/ng/directive/ngBind.js +++ b/src/ng/directive/ngBind.js @@ -51,23 +51,22 @@ */ -var ngBindDirective = ngDirective({ - compile: function ngBindCompile(templateElement) { - templateElement.addClass('ng-binding'); - - return function ngBindLink(scope, element, attr) { - element.data('$binding', attr.ngBind); - element = element[0]; - - scope.$watch(attr.ngBind, function ngBindWatchAction(value) { - // We are purposefully using == here rather than === because we want to - // catch when value is "null or undefined" - // jshint -W041 - element.textContent = (value == undefined ? '' : value); - }); - }; - } -}); +var ngBindDirective = ['$compile', function($compile) { + return { + restrict: 'AC', + compile: function(templateElement) { + return function (scope, element, attr) { + $compile.$$addBindingInfo(element, attr.ngBind); + scope.$watch(attr.ngBind, function ngBindWatchAction(value) { + // We are purposefully using == here rather than === because we want to + // catch when value is "null or undefined" + // jshint -W041 + element.text(value == undefined ? '' : value); + }); + }; + } + }; +}]; /** @@ -121,11 +120,10 @@ var ngBindDirective = ngDirective({ */ -var ngBindTemplateDirective = ['$interpolate', function($interpolate) { +var ngBindTemplateDirective = ['$interpolate', '$compile', function($interpolate, $compile) { return function(scope, element, attr) { - // TODO: move this to scenario runner var interpolateFn = $interpolate(element.attr(attr.$attr.ngBindTemplate)); - element.addClass('ng-binding').data('$binding', interpolateFn); + $compile.$$addBindingInfo(element, interpolateFn); attr.$observe('ngBindTemplate', function(value) { element.text(value); }); @@ -178,14 +176,13 @@ var ngBindTemplateDirective = ['$interpolate', function($interpolate) { */ -var ngBindHtmlDirective = ['$sce', '$parse', function($sce, $parse) { +var ngBindHtmlDirective = ['$sce', '$parse', '$compile', function($sce, $parse, $compile) { return { restrict: 'A', - compile: function ngBindCompile(tElement, tAttrs) { - tElement.addClass('ng-binding'); + compile: function (tElement, tAttrs) { - return function ngBindLink(scope, element, attr) { - element.data('$binding', attr.ngBindHtml); + return function (scope, element, attr) { + $compile.$$addBindingInfo(element, attr.ngBindHtml); var ngBindHtmlGetter = $parse(attr.ngBindHtml); var ngBindHtmlWatch = $parse(attr.ngBindHtml, function getStringValue(value) { return (value || '').toString(); diff --git a/src/ng/directive/select.js b/src/ng/directive/select.js index 8bb93c56ceec..237c29e8791d 100644 --- a/src/ng/directive/select.js +++ b/src/ng/directive/select.js @@ -115,7 +115,7 @@ var ngOptionsMinErr = minErr('ngOptions'); Select bogus.

- Currently selected: {{ {selected_color:myColor} }} + Currently selected: {{ {selected_color:myColor} }}
@@ -123,13 +123,14 @@ var ngOptionsMinErr = minErr('ngOptions'); it('should check ng-options', function() { - expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('red'); + var selectedColor = element(by.binding(' {selected_color:myColor} ')); + expect(selectedColor.getText()).toMatch('red'); element.all(by.model('myColor')).first().click(); element.all(by.css('select[ng-model="myColor"] option')).first().click(); - expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('black'); + expect(selectedColor.getText()).toMatch('black'); element(by.css('.nullable select[ng-model="myColor"]')).click(); element.all(by.css('.nullable select[ng-model="myColor"] option')).first().click(); - expect(element(by.binding('{selected_color:myColor}')).getText()).toMatch('null'); + expect(selectedColor.getText()).toMatch('null'); }); diff --git a/src/ng/filter/filters.js b/src/ng/filter/filters.js index 91cb588aff75..72ca9d7b47fd 100644 --- a/src/ng/filter/filters.js +++ b/src/ng/filter/filters.js @@ -480,7 +480,7 @@ function dateFilter($locale) { it('should jsonify filtered objects', function() { - expect(element(by.binding("{'name':'value'}")).getText()).toMatch(/\{\n "name": ?"value"\n}/); + expect(element(by.binding(" {'name':'value'} | json ")).getText()).toMatch(/\{\n "name": ?"value"\n}/); }); diff --git a/src/ng/filter/limitTo.js b/src/ng/filter/limitTo.js index 52abd260b9a2..6f01aa9c1f86 100644 --- a/src/ng/filter/limitTo.js +++ b/src/ng/filter/limitTo.js @@ -40,8 +40,8 @@ var numLimitInput = element(by.model('numLimit')); var letterLimitInput = element(by.model('letterLimit')); - var limitedNumbers = element(by.binding('numbers | limitTo:numLimit')); - var limitedLetters = element(by.binding('letters | limitTo:letterLimit')); + var limitedNumbers = element(by.binding(' numbers | limitTo:numLimit ')); + var limitedLetters = element(by.binding(' letters | limitTo:letterLimit ')); it('should limit the number array to first three items', function() { expect(numLimitInput.getAttribute('value')).toBe('3'); diff --git a/src/ngScenario/Scenario.js b/src/ngScenario/Scenario.js index 6cf69d84ce79..4f3199028e85 100644 --- a/src/ngScenario/Scenario.js +++ b/src/ngScenario/Scenario.js @@ -304,9 +304,7 @@ _jQuery.fn.bindings = function(windowJquery, bindExp) { var element = windowJquery(this), bindings; if (bindings = element.data('$binding')) { - if (!angular.isArray(bindings)) { - bindings = [bindings]; - } + for(var expressions = [], binding, j=0, jj=bindings.length; j{{1+2}}'); + angular.bootstrap(element); + expect(element.hasClass('ng-scope')).toBe(false); + dealoc(element); + + // We pass the false to prevent the page actually reloading + angular.reloadWithDebugInfo(false); + + element = jqLite('
{{1+2}}
'); + angular.bootstrap(element); + expect(element.hasClass('ng-scope')).toBe(true); + dealoc(element); + }); + }); + + describe('startingElementHtml', function(){ it('should show starting element tag only', function(){ expect(startingTag('
text
')). diff --git a/test/ng/compileSpec.js b/test/ng/compileSpec.js index 04f6ad9969d5..b23d212a99b7 100755 --- a/test/ng/compileSpec.js +++ b/test/ng/compileSpec.js @@ -294,10 +294,15 @@ describe('$compile', function() { describe('compile phase', function() { - it('should attach scope to the document node when it is compiled explicitly', inject(function($document){ - $compile($document)($rootScope); - expect($document.scope()).toBe($rootScope); - })); + it('should attach scope to the document node when it is compiled explicitly', function() { + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); + inject(function($document){ + $compile($document)($rootScope); + expect($document.scope()).toBe($rootScope); + }); + }); it('should wrap root text nodes in spans', inject(function($compile, $rootScope) { element = jqLite('
A<a>B</a>C
'); @@ -464,7 +469,7 @@ describe('$compile', function() { toEqual('
'); expect($exceptionHandler.errors[2][0]).toEqual('LinkingError'); expect(ie($exceptionHandler.errors[2][1])). - toEqual('
'); + toEqual('
'); // crazy stuff to make IE happy @@ -1981,7 +1986,10 @@ describe('$compile', function() { describe('scope', function() { var iscope; - beforeEach(module(function() { + beforeEach(module(function($compileProvider) { + + $compileProvider.enableDebugInfo(true); + forEach(['', 'a', 'b'], function(name) { directive('scope' + uppercase(name), function(log) { return { @@ -2088,11 +2096,18 @@ describe('$compile', function() { })); - it('should allow creation of new scopes', inject(function($rootScope, $compile, log) { - element = $compile('
')($rootScope); - expect(log).toEqual('2; log-2-1; LOG'); - expect(element.find('span').hasClass('ng-scope')).toBe(true); - })); + it('should allow creation of new scopes', function() { + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); + + inject(function($rootScope, $compile, log) { + element = $compile('
')($rootScope); + expect(log).toEqual('2; log-2-1; LOG'); + expect(element.find('span').hasClass('ng-scope')).toBe(true); + }); + }); it('should allow creation of new isolated scopes for directives', inject( @@ -2232,6 +2247,10 @@ describe('$compile', function() { describe('scope()/isolate() scope getters', function() { + beforeEach(module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + })); + describe('with no directives', function() { it('should return the scope of the parent node', inject( @@ -2491,13 +2510,36 @@ describe('$compile', function() { })); }); - it('should decorate the binding with ng-binding and interpolation function', inject( - function($compile, $rootScope) { + describe("decorating with binding info", function() { + + it('should not occur if `enableDebugInfo` is falsy', function() { + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(false); + }); + + inject(function($compile, $rootScope) { element = $compile('
{{1+2}}
')($rootScope); - expect(element.hasClass('ng-binding')).toBe(true); - expect(element.data('$binding')[0].exp).toEqual('{{1+2}}'); - })); + expect(element.hasClass('ng-binding')).toBe(false); + expect(element.data('$binding')).toBeUndefined(); + }); + }); + + it('should occur if `enableDebugInfo` has been called', function() { + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); + + inject( + function($compile, $rootScope) { + element = $compile('
{{1+2}}
')($rootScope); + expect(element.hasClass('ng-binding')).toBe(true); + expect(element.data('$binding')).toEqual(['1+2']); + }); + }); + }); it('should observe interpolated attrs', inject(function($rootScope, $compile) { $compile('
')($rootScope); @@ -2947,7 +2989,10 @@ describe('$compile', function() { describe('isolated locals', function() { var componentScope, regularScope; - beforeEach(module(function() { + beforeEach(module(function($compileProvider) { + + $compileProvider.enableDebugInfo(true); + directive('myComponent', function() { return { scope: { @@ -3467,6 +3512,11 @@ describe('$compile', function() { describe('controller', function() { + + beforeEach(module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + })); + it('should get required controller', function() { module(function() { directive('main', function(log) { @@ -4230,12 +4280,17 @@ describe('$compile', function() { - it('should not leak if two "element" transclusions are on the same element', function () { + it('should not leak if two "element" transclusions are on the same element (with debug info)', function () { if (jQuery) { // jQuery 2.x doesn't expose the cache storage. return; } + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); + inject(function($compile, $rootScope) { expect(jqLiteCacheSize()).toEqual(0); @@ -4257,12 +4312,48 @@ describe('$compile', function() { }); - it('should not leak if two "element" transclusions are on the same element', function () { + it('should not leak if two "element" transclusions are on the same element (without debug info)', function () { if (jQuery) { // jQuery 2.x doesn't expose the cache storage. return; } + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(false); + }); + + inject(function($compile, $rootScope) { + expect(jqLiteCacheSize()).toEqual(0); + + element = $compile('
{{x}}
')($rootScope); + expect(jqLiteCacheSize()).toEqual(0); + + $rootScope.$apply('xs = [0,1]'); + expect(jqLiteCacheSize()).toEqual(0); + + $rootScope.$apply('xs = [0]'); + expect(jqLiteCacheSize()).toEqual(0); + + $rootScope.$apply('xs = []'); + expect(jqLiteCacheSize()).toEqual(0); + + element.remove(); + expect(jqLiteCacheSize()).toEqual(0); + }); + }); + + + it('should not leak if two "element" transclusions are on the same element (with debug info)', function () { + if (jQuery) { + // jQuery 2.x doesn't expose the cache storage. + return; + } + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); + inject(function($compile, $rootScope) { expect(jqLiteCacheSize()).toEqual(0); element = $compile('
{{x}}
')($rootScope); @@ -4287,9 +4378,50 @@ describe('$compile', function() { }); }); + + it('should not leak if two "element" transclusions are on the same element (without debug info)', function () { + if (jQuery) { + // jQuery 2.x doesn't expose the cache storage. + return; + } + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(false); + }); + + inject(function($compile, $rootScope) { + expect(jqLiteCacheSize()).toEqual(0); + element = $compile('
{{x}}
')($rootScope); + + $rootScope.$apply('xs = [0,1]'); + // At this point we have a bunch of comment placeholders but no real transcluded elements + // So the cache only contains the root element's data + expect(jqLiteCacheSize()).toEqual(0); + + $rootScope.$apply('val = true'); + // Now we have two concrete transcluded elements plus some comments so two more cache items + expect(jqLiteCacheSize()).toEqual(0); + + $rootScope.$apply('val = false'); + // Once again we only have comments so no transcluded elements and the cache is back to just + // the root element + expect(jqLiteCacheSize()).toEqual(0); + + element.remove(); + // Now we've even removed the root element along with its cache + expect(jqLiteCacheSize()).toEqual(0); + }); + }); + + if (jQuery) { describe('cleaning up after a replaced element', function () { var $compile, xs; + + beforeEach(module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + })); + beforeEach(inject(function (_$compile_) { $compile = _$compile_; xs = [0, 1]; @@ -4301,7 +4433,7 @@ describe('$compile', function() { element = $compile('
{{x}}
')($rootScope); $rootScope.$apply('xs = [' + xs + ']'); - firstRepeatedElem = element.children('.ng-scope').eq(0); + firstRepeatedElem = element.children().eq(0); expect(firstRepeatedElem.data('$scope')).toBeDefined(); privateData = jQuery._data(firstRepeatedElem[0]); @@ -5200,7 +5332,9 @@ describe('$compile', function() { })); }); inject(function($compile) { - element = $compile('
')($rootScope); + // We need to wrap the transclude directive's element in a parent element so that the + // cloned element gets deallocated/cleaned up correctly + element = $compile('
')($rootScope); expect(capturedTranscludeCtrl).toBeTruthy(); }); }); @@ -5902,175 +6036,187 @@ describe('$compile', function() { })); - it('should set up and destroy the transclusion scopes correctly', - inject(function($compile, $rootScope) { - element = $compile( - '
' + - '
' + - '
' + - '
' - )($rootScope); - $rootScope.$apply('val0 = true; val1 = true; val2 = true'); - - // At this point we should have something like: - // - //
- // - // - // - //
- // - // - // - //
- // - //
- // - // - // - //
- // - // - //
- var ngIfStartScope = element.find('div').eq(0).scope(); - var ngIfEndScope = element.find('div').eq(1).scope(); - - expect(ngIfStartScope.$id).toEqual(ngIfEndScope.$id); - - var ngIf1Scope = element.find('span').eq(0).scope(); - var ngIf2Scope = element.find('span').eq(1).scope(); - - expect(ngIf1Scope.$id).not.toEqual(ngIf2Scope.$id); - expect(ngIf1Scope.$parent.$id).toEqual(ngIf2Scope.$parent.$id); + it('should set up and destroy the transclusion scopes correctly', function() { - $rootScope.$apply('val1 = false'); - - // Now we should have something like: - // - //
- // - //
- // - //
- //
- // - // - // - //
- // - //
- - expect(ngIfStartScope.$$destroyed).not.toEqual(true); - expect(ngIf1Scope.$$destroyed).toEqual(true); - expect(ngIf2Scope.$$destroyed).not.toEqual(true); - - $rootScope.$apply('val0 = false'); - - // Now we should have something like: - // - //
- // - //
- - expect(ngIfStartScope.$$destroyed).toEqual(true); - expect(ngIf1Scope.$$destroyed).toEqual(true); - expect(ngIf2Scope.$$destroyed).toEqual(true); - })); - - - it('should set up and destroy the transclusion scopes correctly', - inject(function($compile, $rootScope) { - element = $compile( - '
' + - '
' + - '
' + - '
' - )($rootScope); - - // To begin with there is (almost) nothing: - //
- // - //
- - expect(element.scope().$id).toEqual($rootScope.$id); - - // Now we create all the elements - $rootScope.$apply('val0 = [1]; val1 = true; val2 = true'); - - // At this point we have: - // - //
- // - // - // - //
- //
- // - // - // - //
- //
- // - // - //
- var ngIf1Scope = element.find('div').eq(0).scope(); - var ngIf2Scope = element.find('div').eq(1).scope(); - var ngRepeatScope = ngIf1Scope.$parent; - - expect(ngIf1Scope.$id).not.toEqual(ngIf2Scope.$id); - expect(ngIf1Scope.$parent.$id).toEqual(ngRepeatScope.$id); - expect(ngIf2Scope.$parent.$id).toEqual(ngRepeatScope.$id); + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); - // What is happening here?? - // We seem to have a repeater scope which doesn't actually match to any element - expect(ngRepeatScope.$parent.$id).toEqual($rootScope.$id); + inject(function($compile, $rootScope) { + element = $compile( + '
' + + '
' + + '
' + + '
' + )($rootScope); + $rootScope.$apply('val0 = true; val1 = true; val2 = true'); + + // At this point we should have something like: + // + //
+ // + // + // + //
+ // + // + // + //
+ // + //
+ // + // + // + //
+ // + // + //
+ var ngIfStartScope = element.find('div').eq(0).scope(); + var ngIfEndScope = element.find('div').eq(1).scope(); + + expect(ngIfStartScope.$id).toEqual(ngIfEndScope.$id); + + var ngIf1Scope = element.find('span').eq(0).scope(); + var ngIf2Scope = element.find('span').eq(1).scope(); + + expect(ngIf1Scope.$id).not.toEqual(ngIf2Scope.$id); + expect(ngIf1Scope.$parent.$id).toEqual(ngIf2Scope.$parent.$id); + + $rootScope.$apply('val1 = false'); + + // Now we should have something like: + // + //
+ // + //
+ // + //
+ //
+ // + // + // + //
+ // + //
+ + expect(ngIfStartScope.$$destroyed).not.toEqual(true); + expect(ngIf1Scope.$$destroyed).toEqual(true); + expect(ngIf2Scope.$$destroyed).not.toEqual(true); + + $rootScope.$apply('val0 = false'); + + // Now we should have something like: + // + //
+ // + //
+ + expect(ngIfStartScope.$$destroyed).toEqual(true); + expect(ngIf1Scope.$$destroyed).toEqual(true); + expect(ngIf2Scope.$$destroyed).toEqual(true); + }); + }); - // Now remove the first ngIf element from the first item in the repeater - $rootScope.$apply('val1 = false'); + it('should set up and destroy the transclusion scopes correctly', function() { - // At this point we should have: - // - //
- // - // - // - // - // - //
- // - // - // - //
- // - expect(ngRepeatScope.$$destroyed).toEqual(false); - expect(ngIf1Scope.$$destroyed).toEqual(true); - expect(ngIf2Scope.$$destroyed).toEqual(false); + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); - // Now remove the second ngIf element from the first item in the repeater - $rootScope.$apply('val2 = false'); + inject(function($compile, $rootScope) { + element = $compile( + '
' + + '
' + + '
' + + '
' + )($rootScope); - // We are mostly back to where we started - // - //
- // - // - // - // - //
- - expect(ngRepeatScope.$$destroyed).toEqual(false); - expect(ngIf1Scope.$$destroyed).toEqual(true); - expect(ngIf2Scope.$$destroyed).toEqual(true); - - // Finally remove the repeat items - $rootScope.$apply('val0 = []'); - - // Somehow this ngRepeat scope knows how to destroy itself... - expect(ngRepeatScope.$$destroyed).toEqual(true); - expect(ngIf1Scope.$$destroyed).toEqual(true); - expect(ngIf2Scope.$$destroyed).toEqual(true); - })); + // To begin with there is (almost) nothing: + //
+ // + //
+ + expect(element.scope().$id).toEqual($rootScope.$id); + + // Now we create all the elements + $rootScope.$apply('val0 = [1]; val1 = true; val2 = true'); + + // At this point we have: + // + //
+ // + // + // + //
+ //
+ // + // + // + //
+ //
+ // + // + //
+ var ngIf1Scope = element.find('div').eq(0).scope(); + var ngIf2Scope = element.find('div').eq(1).scope(); + var ngRepeatScope = ngIf1Scope.$parent; + + expect(ngIf1Scope.$id).not.toEqual(ngIf2Scope.$id); + expect(ngIf1Scope.$parent.$id).toEqual(ngRepeatScope.$id); + expect(ngIf2Scope.$parent.$id).toEqual(ngRepeatScope.$id); + + // What is happening here?? + // We seem to have a repeater scope which doesn't actually match to any element + expect(ngRepeatScope.$parent.$id).toEqual($rootScope.$id); + + + // Now remove the first ngIf element from the first item in the repeater + $rootScope.$apply('val1 = false'); + + // At this point we should have: + // + //
+ // + // + // + // + // + //
+ // + // + // + //
+ // + expect(ngRepeatScope.$$destroyed).toEqual(false); + expect(ngIf1Scope.$$destroyed).toEqual(true); + expect(ngIf2Scope.$$destroyed).toEqual(false); + + // Now remove the second ngIf element from the first item in the repeater + $rootScope.$apply('val2 = false'); + + // We are mostly back to where we started + // + //
+ // + // + // + // + //
+ + expect(ngRepeatScope.$$destroyed).toEqual(false); + expect(ngIf1Scope.$$destroyed).toEqual(true); + expect(ngIf2Scope.$$destroyed).toEqual(true); + + // Finally remove the repeat items + $rootScope.$apply('val0 = []'); + + // Somehow this ngRepeat scope knows how to destroy itself... + expect(ngRepeatScope.$$destroyed).toEqual(true); + expect(ngIf1Scope.$$destroyed).toEqual(true); + expect(ngIf2Scope.$$destroyed).toEqual(true); + }); + }); it('should throw error if unterminated', function () { module(function($compileProvider) { diff --git a/test/ng/directive/formSpec.js b/test/ng/directive/formSpec.js index 21e21f3234dd..f9d7aecee909 100644 --- a/test/ng/directive/formSpec.js +++ b/test/ng/directive/formSpec.js @@ -15,6 +15,11 @@ describe('form', function() { }); })); + // Let's turn on the debugInfo so that we can use element.scope() + beforeEach(module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + })); + beforeEach(inject(function($injector, $sniffer) { $compile = $injector.get('$compile'); scope = $injector.get('$rootScope'); @@ -496,6 +501,7 @@ describe('form', function() { it('should chain nested forms in repeater', function() { + doc = jqLite( '' + '' + diff --git a/test/ng/directive/inputSpec.js b/test/ng/directive/inputSpec.js index a569dc5f3e6a..0975b55c099e 100644 --- a/test/ng/directive/inputSpec.js +++ b/test/ng/directive/inputSpec.js @@ -452,6 +452,8 @@ describe('ngModel', function() { expect(element).toBeInvalid(); expect(element).toHaveClass('ng-invalid-required'); + + dealoc(element); })); diff --git a/test/ng/directive/ngBindSpec.js b/test/ng/directive/ngBindSpec.js index 704932b09085..646a5d806de8 100644 --- a/test/ng/directive/ngBindSpec.js +++ b/test/ng/directive/ngBindSpec.js @@ -3,6 +3,9 @@ describe('ngBind*', function() { var element; + beforeEach(module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + })); afterEach(function() { dealoc(element); @@ -122,13 +125,6 @@ describe('ngBind*', function() { describe('ngBindHtml', function() { - it('should add ng-binding class to the element in compile phase', inject(function($compile) { - var element = jqLite('
'); - $compile(element); - expect(element.hasClass('ng-binding')).toBe(true); - })); - - describe('SCE disabled', function() { beforeEach(function() { module(function($sceProvider) { $sceProvider.enabled(false); }); diff --git a/test/ng/directive/ngClassSpec.js b/test/ng/directive/ngClassSpec.js index e789d141440d..2475e9101305 100644 --- a/test/ng/directive/ngClassSpec.js +++ b/test/ng/directive/ngClassSpec.js @@ -39,9 +39,9 @@ describe('ngClass', function() { })); - it('should support adding multiple classes conditionally via a map of class names to boolean' + + it('should support adding multiple classes conditionally via a map of class names to boolean ' + 'expressions', inject(function($rootScope, $compile) { - var element = $compile( + element = $compile( '
' + '
')($rootScope); @@ -58,12 +58,13 @@ describe('ngClass', function() { expect(element.hasClass('A')).toBeTruthy(); expect(element.hasClass('B')).toBeTruthy(); expect(element.hasClass('AnotB')).toBeFalsy(); + })); it('should remove classes when the referenced object is the same but its property is changed', inject(function($rootScope, $compile) { - var element = $compile('
')($rootScope); + element = $compile('
')($rootScope); $rootScope.classes = { A: true, B: true }; $rootScope.$digest(); expect(element.hasClass('A')).toBeTruthy(); @@ -124,7 +125,7 @@ describe('ngClass', function() { $rootScope.$digest(); $rootScope.dynCls = 'foo'; $rootScope.$digest(); - expect(element[0].className).toBe('ui-panel ui-selected ng-scope foo'); + expect(element[0].className).toBe('ui-panel ui-selected foo'); })); @@ -132,7 +133,7 @@ describe('ngClass', function() { element = $compile('
')($rootScope); $rootScope.dynCls = 'panel'; $rootScope.$digest(); - expect(element[0].className).toBe('panel bar ng-scope'); + expect(element[0].className).toBe('panel bar'); })); @@ -142,7 +143,7 @@ describe('ngClass', function() { $rootScope.$digest(); $rootScope.dynCls = 'window'; $rootScope.$digest(); - expect(element[0].className).toBe('bar ng-scope window'); + expect(element[0].className).toBe('bar window'); })); @@ -153,7 +154,7 @@ describe('ngClass', function() { element.addClass('foo'); $rootScope.dynCls = ''; $rootScope.$digest(); - expect(element[0].className).toBe('ng-scope'); + expect(element[0].className).toBe(''); })); @@ -161,7 +162,7 @@ describe('ngClass', function() { element = $compile('
')($rootScope); $rootScope.dynCls = [undefined, null]; $rootScope.$digest(); - expect(element[0].className).toBe('ng-scope'); + expect(element[0].className).toBe(''); })); @@ -364,10 +365,14 @@ describe('ngClass', function() { describe('ngClass animations', function() { var body, element, $rootElement; + afterEach(function() { + dealoc(element); + }); + it("should avoid calling addClass accidentally when removeClass is going on", function() { module('ngAnimateMock'); inject(function($compile, $rootScope, $animate, $timeout) { - var element = angular.element('
'); + element = angular.element('
'); var body = jqLite(document.body); body.append(element); $compile(element)($rootScope); @@ -434,7 +439,7 @@ describe('ngClass animations', function() { digestQueue.shift()(); $rootScope.val = 'crazy'; - var element = angular.element('
'); + element = angular.element('
'); jqLite($document[0].body).append($rootElement); $compile(element)($rootScope); @@ -481,7 +486,7 @@ describe('ngClass animations', function() { $rootScope.two = true; $rootScope.three = true; - var element = angular.element('
'); + element = angular.element('
'); $compile(element)($rootScope); $rootScope.$digest(); @@ -511,6 +516,7 @@ describe('ngClass animations', function() { expect(item.args[2]).toBe('two'); expect($animate.queue.length).toBe(0); + }); }); }); diff --git a/test/ng/directive/ngIfSpec.js b/test/ng/directive/ngIfSpec.js index acbbb0627cc9..3c6a9f891802 100755 --- a/test/ng/directive/ngIfSpec.js +++ b/test/ng/directive/ngIfSpec.js @@ -5,6 +5,7 @@ describe('ngIf', function () { beforeEach(module(function(_$compileProvider_) { $compileProvider = _$compileProvider_; + $compileProvider.enableDebugInfo(true); })); beforeEach(inject(function ($rootScope, _$compile_) { $scope = $rootScope.$new(); diff --git a/test/ng/directive/ngIncludeSpec.js b/test/ng/directive/ngIncludeSpec.js index 828c6d2056fb..113e53785480 100644 --- a/test/ng/directive/ngIncludeSpec.js +++ b/test/ng/directive/ngIncludeSpec.js @@ -182,34 +182,42 @@ describe('ngInclude', function() { })); - it('should create child scope and destroy old one', inject( + it('should create child scope and destroy old one', function() { + + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); + + inject( function($rootScope, $compile, $httpBackend) { - $httpBackend.whenGET('url1').respond('partial {{$parent.url}}'); - $httpBackend.whenGET('url2').respond(404); + $httpBackend.whenGET('url1').respond('partial {{$parent.url}}'); + $httpBackend.whenGET('url2').respond(404); - element = $compile('
')($rootScope); - expect(element.children().scope()).toBeFalsy(); + element = $compile('
')($rootScope); + expect(element.children().scope()).toBeFalsy(); - $rootScope.url = 'url1'; - $rootScope.$digest(); - $httpBackend.flush(); - expect(element.children().scope().$parent).toBe($rootScope); - expect(element.text()).toBe('partial url1'); + $rootScope.url = 'url1'; + $rootScope.$digest(); + $httpBackend.flush(); + expect(element.children().scope().$parent).toBe($rootScope); + expect(element.text()).toBe('partial url1'); - $rootScope.url = 'url2'; - $rootScope.$digest(); - $httpBackend.flush(); - expect($rootScope.$$childHead).toBeFalsy(); - expect(element.text()).toBe(''); + $rootScope.url = 'url2'; + $rootScope.$digest(); + $httpBackend.flush(); + expect($rootScope.$$childHead).toBeFalsy(); + expect(element.text()).toBe(''); - $rootScope.url = 'url1'; - $rootScope.$digest(); - expect(element.children().scope().$parent).toBe($rootScope); + $rootScope.url = 'url1'; + $rootScope.$digest(); + expect(element.children().scope().$parent).toBe($rootScope); - $rootScope.url = null; - $rootScope.$digest(); - expect($rootScope.$$childHead).toBeFalsy(); - })); + $rootScope.url = null; + $rootScope.$digest(); + expect($rootScope.$$childHead).toBeFalsy(); + }); + + }); it('should do xhr request and cache it', diff --git a/test/ng/directive/ngInitSpec.js b/test/ng/directive/ngInitSpec.js index 9ed930ad39eb..2b6b2693390a 100644 --- a/test/ng/directive/ngInitSpec.js +++ b/test/ng/directive/ngInitSpec.js @@ -28,8 +28,9 @@ describe('ngInit', function() { it("should be evaluated after ngController", function() { - module(function($controllerProvider) { + module(function($controllerProvider, $compileProvider) { $controllerProvider.register('TestCtrl', function($scope) {}); + $compileProvider.enableDebugInfo(true); }); inject(function($rootScope, $compile) { element = $compile('
' + - '
{{name}}
' + - '')($rootScope); - $rootScope.$apply(); + it('should properly create and destroy child scopes', function() { - var getChildScope = function() { return element.find('div').scope(); }; + module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + }); - expect(getChildScope()).toBeUndefined(); + inject(function($rootScope, $compile) { + element = $compile( + '' + + '
{{name}}
' + + '
')($rootScope); + $rootScope.$apply(); - $rootScope.url = 'a'; - $rootScope.$apply(); - var child1 = getChildScope(); - expect(child1).toBeDefined(); - spyOn(child1, '$destroy'); + var getChildScope = function() { return element.find('div').scope(); }; - $rootScope.url = 'x'; - $rootScope.$apply(); - expect(getChildScope()).toBeUndefined(); - expect(child1.$destroy).toHaveBeenCalled(); + expect(getChildScope()).toBeUndefined(); - $rootScope.url = 'a'; - $rootScope.$apply(); - var child2 = getChildScope(); - expect(child2).toBeDefined(); - expect(child2).not.toBe(child1); - })); + $rootScope.url = 'a'; + $rootScope.$apply(); + var child1 = getChildScope(); + expect(child1).toBeDefined(); + spyOn(child1, '$destroy'); + + $rootScope.url = 'x'; + $rootScope.$apply(); + expect(getChildScope()).toBeUndefined(); + expect(child1.$destroy).toHaveBeenCalled(); + + $rootScope.url = 'a'; + $rootScope.$apply(); + var child2 = getChildScope(); + expect(child2).toBeDefined(); + expect(child2).not.toBe(child1); + }); + }); it("should interoperate with other transclusion directives like ngRepeat", inject(function($rootScope, $compile) { diff --git a/test/ngRoute/directive/ngViewSpec.js b/test/ngRoute/directive/ngViewSpec.js index 2aa286e85f5e..ab504169a5ca 100644 --- a/test/ngRoute/directive/ngViewSpec.js +++ b/test/ngRoute/directive/ngViewSpec.js @@ -103,9 +103,10 @@ describe('ngView', function() { it('should support string controller declaration', function() { var MyCtrl = jasmine.createSpy('MyCtrl'); - module(function($controllerProvider, $routeProvider) { + module(function($controllerProvider, $routeProvider, $compileProvider) { $controllerProvider.register('MyCtrl', ['$scope', MyCtrl]); $routeProvider.when('/foo', {controller: 'MyCtrl', templateUrl: '/tpl.html'}); + $compileProvider.enableDebugInfo(true); }); inject(function($route, $location, $rootScope, $templateCache) { @@ -489,8 +490,9 @@ describe('ngView', function() { $scope.ctrl = this; } - module(function($routeProvider) { + module(function($routeProvider, $compileProvider) { $routeProvider.when('/foo', {templateUrl: 'tpl.html', controller: MyCtrl}); + $compileProvider.enableDebugInfo(true); }); inject(function($templateCache, $location, $rootScope, $route) { @@ -517,8 +519,9 @@ describe('ngView', function() { it('should not set $scope or $controllerController on top level text elements in the view', function() { function MyCtrl($scope) {} - module(function($routeProvider) { + module(function($routeProvider, $compileProvider) { $routeProvider.when('/foo', {templateUrl: 'tpl.html', controller: MyCtrl}); + $compileProvider.enableDebugInfo(true); }); inject(function($templateCache, $location, $rootScope, $route) { diff --git a/test/ngScenario/dslSpec.js b/test/ngScenario/dslSpec.js index 80d4165bd9ef..e30c0e1ed92a 100644 --- a/test/ngScenario/dslSpec.js +++ b/test/ngScenario/dslSpec.js @@ -9,6 +9,10 @@ describe("angular.scenario.dsl", function() { dealoc(element); }); + beforeEach(module(function($compileProvider) { + $compileProvider.enableDebugInfo(true); + })); + beforeEach(module('ngSanitize')); beforeEach(inject(function($injector) {