diff --git a/.jscs.json b/.jscs.json index e2307d167704..05d53984d38b 100644 --- a/.jscs.json +++ b/.jscs.json @@ -1,3 +1,4 @@ { - "disallowKeywords": ["with"] + "disallowKeywords": ["with"], + "disallowTrailingWhitespace": true } diff --git a/.jscs.json.todo b/.jscs.json.todo index 6f6f041672c2..b7e82bc2b996 100644 --- a/.jscs.json.todo +++ b/.jscs.json.todo @@ -13,7 +13,6 @@ "disallowImplicitTypeConversion": ["string"], "disallowMultipleLineBreaks": true, "disallowKeywordsOnNewLine": ["else"], - "disallowTrailingWhitespace": true, "requireLineFeedAtFileEnd": true, "validateJSDoc": { "checkParamNames": true, diff --git a/.travis.yml b/.travis.yml index 6a24af3fd41b..d22001fc90ef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,12 +2,19 @@ language: node_js node_js: - 0.10 +branches: + except: + - /^g3_.*$/ + env: matrix: - JOB=unit - - JOB=e2e-chrome - - JOB=e2e-firefox - - JOB=e2e-safari + - JOB=e2e BROWSER=chrome JQVERSION=jqlite + - JOB=e2e BROWSER=firefox JQVERSION=jqlite +# - JOB=e2e BROWSER=safari JQVERSION=jqlite +# - JOB=e2e BROWSER=chrome JQVERSION=jquery +# - JOB=e2e BROWSER=firefox JQVERSION=jquery +# - JOB=e2e BROWSER=safari JQVERSION=jquery global: - SAUCE_USERNAME=angular-ci - SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987 diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e635e9f88bf..777fedb1a0b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,119 @@ + +# 1.2.13 romantic-transclusion (2014-02-14) + + +## Bug Fixes + +- **$animate:** ensure $animate doesn't break natural CSS transitions + ([4f84f6b3](https://github.com/angular/angular.js/commit/4f84f6b3e4210ae1eb14728a46d43dd961700a0c), + [#6019](https://github.com/angular/angular.js/issues/6019)) +- **$compile:** + - ensure element transclusion directives are linked with comment element + ([e7338d3f](https://github.com/angular/angular.js/commit/e7338d3f27e8824196136a18e1c3e0fcf51a0e28), + [#6006](https://github.com/angular/angular.js/issues/6006), [#6101](https://github.com/angular/angular.js/issues/6101)) + - support templates with table content root nodes + ([e7338d3f](https://github.com/angular/angular.js/commit/31c450bcee53d0a3827b7e0a611e9013b2496506), + [#2848](https://github.com/angular/angular.js/issues/2848), [#1459](https://github.com/angular/angular.js/issues/1459), [#3647](https://github.com/angular/angular.js/issues/3647), [#3241](https://github.com/angular/angular.js/issues/3241)) +- **input:** + - don't apply textInput to `` + ([a9fcb0d0](https://github.com/angular/angular.js/commit/a9fcb0d0fc6456f80501b8820d02b04d7c15b6d6), + [#6247](https://github.com/angular/angular.js/issues/6247), [#6231](https://github.com/angular/angular.js/issues/6231)) + - setViewValue on compositionend + ([2b730271](https://github.com/angular/angular.js/commit/2b7302713674506fdbcdc396c38f18dcb90dee8c), + [#6058](https://github.com/angular/angular.js/issues/6058), [#5433](https://github.com/angular/angular.js/issues/5433)) + + +## Features + +- **filterFilter:** support deeply nested predicate objects + ([b4eed8ad](https://github.com/angular/angular.js/commit/b4eed8ad94ce9719540462c1ee969dfd3c6b2355), + [#6215](https://github.com/angular/angular.js/issues/6215)) + + +## Breaking Changes + +- **$animate:** + - due to [4f84f6b3](https://github.com/angular/angular.js/commit/4f84f6b3e4210ae1eb14728a46d43dd961700a0c), + ngClass and {{ class }} will now call the `setClass` + animation callback instead of addClass / removeClass when both a + addClass/removeClass operation is being executed on the element during the animation. + + Please include the setClass animation callback as well as addClass and removeClass within + your JS animations to work with ngClass and {{ class }} directives. + + + - due to [cf5e463a](https://github.com/angular/angular.js/commit/cf5e463abd2c23f62e9c2e6361e6c53048c8910e), + Both the `$animate:before` and `$animate:after` DOM events must be now + registered prior to the $animate operation taking place. The `$animate:close` event + can be registered anytime afterwards. + + DOM callbacks used to fired for each and every animation operation that occurs within the + $animate service provided in the ngAnimate module. This may end up slowing down an + application if 100s of elements are being inserted into the page. Therefore after this + change callbacks are only fired if registered on the element being animated. + + + +# 1.2.12 cauliflower-eradication (2014-02-07) + + +## Bug Fixes + +- **$compile:** retain CSS classes added in cloneAttachFn on asynchronous directives + ([5ed721b9](https://github.com/angular/angular.js/commit/5ed721b9b5e95ae08450e1ae9d5202e7f3f79295), + [#5439](https://github.com/angular/angular.js/issues/5439), [#5617](https://github.com/angular/angular.js/issues/5617)) +- **$http:** + - ignore xhr.responseType setter exception if value is "json" + ([24699ee8](https://github.com/angular/angular.js/commit/24699ee8f04c1f1459be1d36207e654421d58ff0), + [#6115](https://github.com/angular/angular.js/issues/6115), [#6122](https://github.com/angular/angular.js/issues/6122)) + - update httpBackend to use ActiveXObject on IE8 if necessary + ([ef210e5e](https://github.com/angular/angular.js/commit/ef210e5e119db4f5bfc9d2428b19f9b335c4f976), + [#5677](https://github.com/angular/angular.js/issues/5677), [#5679](https://github.com/angular/angular.js/issues/5679)) +- **$locale:** minor grammar amends for the locale `locale_lt` + ([95be253f](https://github.com/angular/angular.js/commit/95be253fe55d35336d425d3d600a36158fc3519d), + [#6164](https://github.com/angular/angular.js/issues/6164)) +- **$q:** make $q.reject support `finally` and `catch` + ([074b0675](https://github.com/angular/angular.js/commit/074b0675a1f97dce07f520f1ae6198ed3c604000), + [#6048](https://github.com/angular/angular.js/issues/6048), [#6076](https://github.com/angular/angular.js/issues/6076)) +- **docs:** clarify doc for "args" in $broadcast and $emit + ([caed2dfe](https://github.com/angular/angular.js/commit/caed2dfe4feeac5d19ecea2dbb1456b7fde21e6d), + [#6047](https://github.com/angular/angular.js/issues/6047)) +- **filterFilter:** don't interpret dots in predicate object fields as paths + ([339a1658](https://github.com/angular/angular.js/commit/339a1658cd9bfa5e322a01c45aa0a1df67e3a842), + [#6005](https://github.com/angular/angular.js/issues/6005), [#6009](https://github.com/angular/angular.js/issues/6009)) +- **http:** make jshint happy + ([6609e3da](https://github.com/angular/angular.js/commit/6609e3da76dd898cfe85f75f23ab2e39fee65fe5)) +- **jqLite:** trim HTML string in jqLite constructor + ([36d37c0e](https://github.com/angular/angular.js/commit/36d37c0e3880c774d20c014ade60d2331beefa15), + [#6053](https://github.com/angular/angular.js/issues/6053)) +- **mocks:** + - rename mock.animate to ngAnimateMock and ensure it contains all test helper code for ngAnimate + ([4224cd51](https://github.com/angular/angular.js/commit/4224cd5182bc93e4a210f75e0a4e4de7f3c544e8), + [#5822](https://github.com/angular/angular.js/issues/5822), [#5917](https://github.com/angular/angular.js/issues/5917)) + - remove usage of $animate.flushNext in favour of queing + ([906fdad0](https://github.com/angular/angular.js/commit/906fdad0f95465842e336e057ea97d0633712189)) + - always call functions injected with `inject` with `this` set to the current spec + ([3bf43903](https://github.com/angular/angular.js/commit/3bf43903397c703aa2e9ba1e1a48dbc9e8286ee2), + [#6102](https://github.com/angular/angular.js/issues/6102)) + - refactor currentSpec to work w/ Jasmine 2 + ([95f0bf9b](https://github.com/angular/angular.js/commit/95f0bf9b526fda8964527c6d4aef1ad50a47f1f3), + [#5662](https://github.com/angular/angular.js/issues/5662)) +- **ngMock:** return false from mock $interval.cancel() when no argument is supplied + ([dd24c783](https://github.com/angular/angular.js/commit/dd24c78373b5d24ecb3b9d19e61e1b3b6c74d155), + [#6103](https://github.com/angular/angular.js/issues/6103)) +- **ngResource:** + - don't filter "$"-prefixed properties from ngResource requests/responses + ([d2e4e499](https://github.com/angular/angular.js/commit/d2e4e499862aeca157dbe7a7422c465e7c79205e), + [#5666](https://github.com/angular/angular.js/issues/5666), [#6080](https://github.com/angular/angular.js/issues/6080), [#6033](https://github.com/angular/angular.js/issues/6033)) + - don't append number to '$' in url param value when encoding URI + ([ce1f1f97](https://github.com/angular/angular.js/commit/ce1f1f97f0ebf77941b2bdaf5e8352d33786524d), + [#6003](https://github.com/angular/angular.js/issues/6003), [#6004](https://github.com/angular/angular.js/issues/6004)) + +## Breaking Changes + +The animation mock module has been renamed from `mock.animate` to `ngAnimateMock`. In addition to the rename, animations will not block within test code even when ngAnimateMock is used. However, all function calls to $animate will be recorded into `$animate.queue` and are available within test code to assert animation calls. In addition, `$animate.triggerReflow()` is now only available when `ngAnimateMock` is used. + + # 1.2.11 cryptocurrency-hyperdeflation (2014-02-03) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c90fdccc276d..cbc281b9b7f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -3,6 +3,9 @@ We'd love for you to contribute to our source code and to make AngularJS even better than it is today! Here are the guidelines we'd like you to follow: +## Code of Conduct +Help us keep Angular open and inclusive. Please read and follow our [Code of Conduct][coc]. + ## Got a Question or Problem? If you have questions about how to use AngularJS, please direct these to the [Google Group][groups] @@ -140,14 +143,6 @@ from the main (upstream) repository: git pull --ff upstream master ``` -### GitHub Pull Request Helper - -We track Pull Requests by attaching labels and assigning to milestones. For some reason GitHub -does not provide a good UI for managing labels on Pull Requests (unlike Issues). We have developed -a simple Chrome Extension that enables you to view (and manage if you have permission) the labels -on Pull Requests. You can get the extension from the Chrome WebStore - -[GitHub PR Helper][github-pr-helper] - ## Coding Rules To ensure consistency throughout the source code, keep these rules in mind as you are working: @@ -258,5 +253,6 @@ You can find out more detailed information about contributing in the [corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html [commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit# [github-pr-helper]: https://chrome.google.com/webstore/detail/github-pr-helper/mokbklfnaddkkbolfldepnkfmanfhpen +[coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md [](https://github.com/igrigorik/ga-beacon) diff --git a/Gruntfile.js b/Gruntfile.js index 123a0d72a574..74ddd1eb9d03 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -23,7 +23,7 @@ module.exports = function(grunt) { parallel: { travis: { tasks: [ - util.parallelTask(['test:unit', 'test:docgen', 'test:promises-aplus', 'tests:docs'], {stream: true}), + util.parallelTask(['test:unit', 'test:promises-aplus'/*, 'tests:docs'*/], {stream: true}), util.parallelTask(['test:e2e']) ] } @@ -77,7 +77,7 @@ module.exports = function(grunt) { tests: { jqlite: 'karma-jqlite.conf.js', jquery: 'karma-jquery.conf.js', - docs: 'karma-docs.conf.js', + //docs: 'karma-docs.conf.js', modules: 'karma-modules.conf.js' }, @@ -86,12 +86,13 @@ module.exports = function(grunt) { jqlite: 'karma-jqlite.conf.js', jquery: 'karma-jquery.conf.js', modules: 'karma-modules.conf.js', - docs: 'karma-docs.conf.js' + //docs: 'karma-docs.conf.js' }, protractor: { normal: 'protractor-conf.js', + jquery: 'protractor-jquery-conf.js', jenkins: 'protractor-jenkins-conf.js' }, @@ -216,9 +217,9 @@ module.exports = function(grunt) { }, - docs: { - process: ['build/docs/*.html', 'build/docs/.htaccess'] - }, + // docs: { + // process: ['build/docs/*.html', 'build/docs/.htaccess'] + // }, "jasmine_node": { projectRoot: 'docs/spec' @@ -285,16 +286,16 @@ module.exports = function(grunt) { //alias tasks - grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus', 'tests:docs', 'test:protractor']); + grunt.registerTask('test', 'Run unit, docs and e2e tests with Karma', ['jshint', 'package','test:unit','test:promises-aplus'/*, 'tests:docs'*/, 'test:protractor']); grunt.registerTask('test:jqlite', 'Run the unit tests with Karma' , ['tests:jqlite']); grunt.registerTask('test:jquery', 'Run the jQuery unit tests with Karma', ['tests:jquery']); grunt.registerTask('test:modules', 'Run the Karma module tests with Karma', ['tests:modules']); - grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package', 'tests:docs']); + grunt.registerTask('test:docs', 'Run the doc-page tests with Karma', ['package'/*, 'tests:docs'*/]); grunt.registerTask('test:unit', 'Run unit, jQuery and Karma module tests with Karma', ['tests:jqlite', 'tests:jquery', 'tests:modules']); grunt.registerTask('test:protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:normal']); + grunt.registerTask('test:jq-protractor', 'Run the end to end tests against jquery with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:jquery']); grunt.registerTask('test:ci-protractor', 'Run the end to end tests with Protractor and keep a test server running in the background', ['webdriver', 'connect:testserver', 'protractor:jenkins']); grunt.registerTask('test:e2e', 'Alias for test:protractor', ['test:protractor']); - grunt.registerTask('test:docgen', ['jasmine_node']); grunt.registerTask('test:promises-aplus',['build:promises-aplus-adapter','shell:promises-aplus-tests']); grunt.registerTask('minify', ['bower','clean', 'build', 'minall']); diff --git a/TRIAGING.md b/TRIAGING.md index a138774d4e57..4eb4c3e63b8d 100644 --- a/TRIAGING.md +++ b/TRIAGING.md @@ -5,7 +5,6 @@ The labels are used later on for planning releases. ## Tips ## -* install [github pr helper extension](https://github.com/petebacondarwin/github-pr-helper) and become 356% more productive * Label "resolution:*" * these tags can be used for labeling a closed issue/PR with a reason why it was closed. (we can add reasons as we need them, right there are only a few rejection reasons. it doesn't make sense to label issues that were fixed or prs that were merged) diff --git a/bower.json b/bower.json index d261c000f2d0..a369d4174dad 100644 --- a/bower.json +++ b/bower.json @@ -2,11 +2,11 @@ "name": "AngularJS", "devDependencies": { "jquery": "1.10.2", - "lunr.js": "0.4.0", - "google-code-prettify": "1.0.0", - "components-font-awesome": "3.1.0", - "bootstrap": "https://raw.github.com/twbs/bootstrap/v2.0.2/docs/assets/bootstrap.zip", + "lunr.js": "0.4.3", + "open-sans-fontface": "1.0.4", + "google-code-prettify": "1.0.1", "closure-compiler": "https://closure-compiler.googlecode.com/files/compiler-20130603.zip", - "ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip" + "ng-closure-runner": "https://raw.github.com/angular/ng-closure-runner/v0.2.3/assets/ng-closure-runner.zip", + "bootstrap": "3.1.1" } } diff --git a/css/angular.css b/css/angular.css index b88e61e483e2..2566640ebb2f 100644 --- a/css/angular.css +++ b/css/angular.css @@ -9,3 +9,8 @@ ng\:form { display: block; } + +.ng-animate-block-transitions { + transition:0s all!important; + -webkit-transition:0s all!important; +} diff --git a/docs/app/assets/css/animations.css b/docs/app/assets/css/animations.css new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/docs/src/templates/css/doc_widgets.css b/docs/app/assets/css/doc_widgets.css similarity index 100% rename from docs/src/templates/css/doc_widgets.css rename to docs/app/assets/css/doc_widgets.css diff --git a/docs/app/assets/css/docs.css b/docs/app/assets/css/docs.css new file mode 100644 index 000000000000..1c38097eeeeb --- /dev/null +++ b/docs/app/assets/css/docs.css @@ -0,0 +1,553 @@ +html, body { + position:relative; + height:100%; +} + +#wrapper { + min-height:100%; + position:relative; + padding-bottom:120px; +} + +.footer { + border-top:20px solid white; + position:absolute; + bottom:0; + left:0; + right:0; + z-index:100; + padding-top: 2em; + background-color: #333; + color: white; + padding-bottom: 2em; +} + + +.header-fixed { + position:fixed; + z-index:1000; + top:0; + left:0; + right:0; +} + +.docs-navbar-primary { + border-radius:0!important; + margin-bottom:0!important; +} + +/* Logo */ +/*.dropdown-menu { + display:none; +} +*/ +h1,h2,h3,h4,h5,h6 { + font-family: "Open Sans"; +} + +.subnav-body { + margin:70px 0 20px; +} + +.header .brand { + padding-top: 6px; + padding-bottom: 0px; +} + +.header .brand img { + margin-top:5px; + height: 30px; +} + +.docs-search { + margin:10px; + padding:4px 0 4px 20px; + background:white; + border-radius:20px; + display:table-cell; + vertical-align:middle; +} + +.docs-search > .search-query { + font-size:14px; + border:0; + width:80%; + color:#555; +} + +.docs-search > .search-icon { + font-size:15px; + margin-right:10px; +} + +.docs-search > .search-query:focus { + outline:0; +} + +/* end: Logo */ + + +.spacer { + height: 1em; +} + + +.icon-cog { + line-height: 13px; +} + +.naked-list, +.naked-list ul, +.naked-list li { + list-style:none; + margin:0; + padding:0; +} + +.nav-index-section a { + font-weight:bold; + font-family: "Open Sans"; + color:black!important; + margin-top:10px; + display:block; +} + +.nav-index-group { + margin-bottom:20px!important; +} + +.nav-index-group-heading { + color:#6F0101; + font-weight:bold; + font-size:1.2em; + padding:0; + margin:0; + border-bottom:1px soild #aaa; + margin-bottom:5px; +} + +.nav-breadcrumb { + margin:4px 0; + padding:0; +} + +.nav-breadcrumb-entry { + font-family: "Open Sans"; + padding:0; + margin:0; + font-size:18px; + display:inline-block; + vertical-align:middle; +} + +.nav-breadcrumb-entry > .divider { + color:#555; + display:inline-block; + padding-left:8px; +} + +.nav-breadcrumb-entry > span, +.nav-breadcrumb-entry > a { + color:#6F0101; +} + +.step-list > li:nth-child(1) { + padding-left:20px; +} + +.step-list > li:nth-child(2) { + padding-left:40px; +} + +.step-list > li:nth-child(3) { + padding-left:60px; +} + +.api-profile-header-heading { + margin:0; + padding:0; +} + +.api-profile-header-structure, +.api-profile-header-structure a { + font-family: "Open Sans"; + font-weight:bold; + color:#999; +} + +.api-profile-section { + margin-top:30px; + padding-top:30px; + border-top:1px solid #aaa; +} + +pre { + padding:15px; + border:1px solid #ddd; + display:block; + border-radius:5px; +} + +.aside-nav a, +.aside-nav a:link, +.aside-nav a:visited, +.aside-nav a:active { + color:#999; +} +.aside-nav a:hover { + color:black; +} + +.api-profile-description > p:first-child { + margin:15px 0; + font-size:18px; +} + +p > code, +code.highlighted { + background:#f4f4f4; + border-radius:5px; + padding:2px 5px; + color:maroon; +} + +.docs-version-jump { + min-width:100%; + max-width:100%; +} + +.picker { + position: relative; + width: auto; + display: inline-block; + margin: 0 0 2px 1.2%; + overflow: hidden; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -ms-border-radius: 4px; + -o-border-radius: 4px; + border-radius: 4px; + font-family: "Open Sans"; + font-weight: 600; + height: auto; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2)); + background-image: -webkit-linear-gradient(#ffffff, #f2f2f2); + background-image: -moz-linear-gradient(#ffffff, #f2f2f2); + background-image: -o-linear-gradient(#ffffff, #f2f2f2); + background-image: linear-gradient(#ffffff, #f2f2f2); +} + +.picker select { + position: relative; + display: block; + min-width: 100%; + width: 120%; + height: 34px; + padding: 6px 30px 6px 15px; + color: #555555; + border: none; + background: transparent; + outline: none; + -webkit-appearance: none; + z-index: 99; + cursor: pointer; + font-size: 16px; +} + +.picker:after { + content:""; + position: absolute; + right: 8%; + top: 50%; + z-index: 0; + color: #999; + width: 0; + margin-top:-2px; + height: 0; + border-top: 6px solid; + border-right: 6px solid transparent; + border-left: 6px solid transparent; +} + +iframe.example { + width: 100%; + border: 1px solid black; +} + +.search-results-frame { + clear:both; + display:table; + width:100%; +} + +.search-results.ng-hide { + display:none; +} + +.search-results-container { + padding-bottom:1em; + border-top:1px solid #111; + background:#181818; + box-shadow:inset 0 0 10px #111; +} + +.search-results-container .search-results-group { + vertical-align:top; + padding:10px 10px; + display:inline-block; +} + +.search-results-group-heading { + font-family: "Open Sans"; + padding-left:10px; + color:white; +} + +.search-results-frame > .search-results-group:first-child > .search-results { + border-right:1px solid #050505; +} + +.search-results-group.col-group-api { width:30%; } +.search-results-group.col-group-guide { width:30%; } +.search-results-group.col-group-tutorial { width:25%; } +.search-results-group.col-group-misc, +.search-results-group.col-group-error { float:right; clear:both; width:15% } + + +.search-results-group.col-group-api .search-result { + width:48%; + display:inline-block; +} + +.search-close { + position: absolute; + bottom: 0; + left: 50%; + margin-left: -100px; + color: white; + text-align: center; + padding: 5px; + background: #333; + border-top-right-radius: 5px; + border-top-left-radius: 5px; + width: 200px; + box-shadow:0 0 10px #111; +} + +.variables-matrix { + border:1px solid #ddd; + width:100%; + margin:10px 0; +} + +.variables-matrix td, +.variables-matrix th { + padding:10px; +} + +.variables-matrix td { + border-top:1px solid #eee; +} + +.variables-matrix td + td, +.variables-matrix th + th { + border-left:1px solid #eee; +} + +.variables-matrix tr:nth-child(even) td { + background:#f5f5f5; +} + +.variables-matrix th { + background:#f1f1f1; +} + +.sup-header { + padding-top:10px; + padding-bottom:5px; + background:rgba(245,245,245,0.88); + box-shadow:0 0 2px #999; +} + +.main-body-grid { + margin-top:120px; + position:relative; +} + +.main-body-grid > .grid-left, +.main-body-grid > .grid-right { + padding:20px 0; +} + +.main-body-grid > .grid-left { + position:fixed; + top:120px; + bottom:0; + padding-bottom:120px; + overflow:auto; +} + +.main-header-grid > .grid-left, +.main-body-grid > .grid-left { + width:260px; +} + +.main-header-grid > .grid-right, +.main-body-grid > .grid-right { + margin-left:270px; + position:relative; +} + +.main-header-grid > .grid-left { + float:left; +} + +.variables-matrix td { + vertical-align:top; + padding:5px; +} + +.type-hint { + display:inline-block; +} + +.variables-matrix .type-hint { + text-align:center; + min-width:60px; + margin:1px 5px; +} + +.type-hint + .type-hint { + margin-top:5px; +} + +.type-hint-expression { + background:purple; +} + +.type-hint-date { + background:pink; +} + +.type-hint-string { + background:#3a87ad; +} + +.type-hint-function { + background:green; +} + +.type-hint-object { + background:#999; +} + +.type-hint-array { + background:#F90;; +} + +.type-hint-boolean { + background:rgb(18, 131, 39); +} + +.type-hint-number { + background:rgb(189, 63, 66); +} + +.runnable-example-frame { + width:100%; + height:300px; + border: 1px solid #ddd; + border-radius:5px; +} + +.runnable-example-tabs { + margin-top:10px; + margin-bottom:20px; +} + +.tutorial-nav { + display:block; +} + +h1 + ul, h1 + ul > li, +h2 + ul, h2 + ul > li, +ul.tutorial-nav, ul.tutorial-nav > li, +.usage > ul, .usage > ul > li, +ul.methods, ul.methods > li, +ul.events, ul.events > li { + list-style:none; + padding:0; +} + +h2 { + border-top:1px solid #eee; + margin-top:30px; + padding-top:30px; +} + +h4 { + margin-top:20px; + padding-top:20px; +} + +.improve-docs { + float:right; +} + +.btn { + color:#428bca; + position: relative; + width: auto; + display: inline-block; + margin: 0 0 2px; + overflow: hidden; + border: 1px solid #e5e5e5; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + -ms-border-radius: 4px; + -o-border-radius: 4px; + border-radius: 4px; + font-family: "Open Sans"; + font-weight: 600; + height: auto; + background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #f2f2f2)); + background-image: -webkit-linear-gradient(#ffffff, #f2f2f2); + background-image: -moz-linear-gradient(#ffffff, #f2f2f2); + background-image: -o-linear-gradient(#ffffff, #f2f2f2); + background-image: linear-gradient(#ffffff, #f2f2f2); +} + +.btn + .btn { + margin-left:10px; +} + +.btn:hover { + color:black!important; + border: 1px solid #ddd!important; + background:white!important; +} + +.view-source { + margin-right:10px; + padding-right:10px; + border-right:1px solid #999; +} + +.return-arguments, +.return-arguments th, +.return-arguments th + th, +.return-arguments td, +.return-arguments td + td { + border-radius:0; + border:0; +} + +.return-arguments td:first-child { + width:100px; +} + +ul.methods > li, +ul.events > li { + margin-bottom:40px; +} diff --git a/docs/app/assets/css/prettify-theme.css b/docs/app/assets/css/prettify-theme.css new file mode 100644 index 000000000000..86595bcea9a6 --- /dev/null +++ b/docs/app/assets/css/prettify-theme.css @@ -0,0 +1,138 @@ +/* GitHub Theme */ +.prettyprint { + background: white; + font-family: Menlo, 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Consolas, monospace; + font-size: 12px; + line-height: 1.5; +} + +.pln { + color: #333333; +} + +@media screen { + .str { + color: #dd1144; + } + + .kwd { + color: #333333; + } + + .com { + color: #999988; + } + + .typ { + color: #445588; + } + + .lit { + color: #445588; + } + + .pun { + color: #333333; + } + + .opn { + color: #333333; + } + + .clo { + color: #333333; + } + + .tag { + color: navy; + } + + .atn { + color: teal; + } + + .atv { + color: #dd1144; + } + + .dec { + color: #333333; + } + + .var { + color: teal; + } + + .fun { + color: #990000; + } +} +@media print, projection { + .str { + color: #006600; + } + + .kwd { + color: #006; + font-weight: bold; + } + + .com { + color: #600; + font-style: italic; + } + + .typ { + color: #404; + font-weight: bold; + } + + .lit { + color: #004444; + } + + .pun, .opn, .clo { + color: #444400; + } + + .tag { + color: #006; + font-weight: bold; + } + + .atn { + color: #440044; + } + + .atv { + color: #006600; + } +} +/* Specify class=linenums on a pre to get line numbering */ +ol.linenums { + margin-top: 0; + margin-bottom: 0; +} + +/* IE indents via margin-left */ +li.L0, +li.L1, +li.L2, +li.L3, +li.L4, +li.L5, +li.L6, +li.L7, +li.L8, +li.L9 { + /* */ +} + +/* Alternate shading for lines */ +li.L1, +li.L3, +li.L5, +li.L7, +li.L9 { + /* */ +} diff --git a/docs/src/templates/css/prettify.css b/docs/app/assets/css/prettify.css similarity index 100% rename from docs/src/templates/css/prettify.css rename to docs/app/assets/css/prettify.css diff --git a/docs/app/assets/img/AngularJS-small.png b/docs/app/assets/img/AngularJS-small.png new file mode 100644 index 000000000000..ab5e20f883c1 Binary files /dev/null and b/docs/app/assets/img/AngularJS-small.png differ diff --git a/docs/app/assets/img/One_Way_Data_Binding.png b/docs/app/assets/img/One_Way_Data_Binding.png new file mode 100644 index 000000000000..60e7e3bf3255 Binary files /dev/null and b/docs/app/assets/img/One_Way_Data_Binding.png differ diff --git a/docs/app/assets/img/Two_Way_Data_Binding.png b/docs/app/assets/img/Two_Way_Data_Binding.png new file mode 100644 index 000000000000..3a9c6d1ecc25 Binary files /dev/null and b/docs/app/assets/img/Two_Way_Data_Binding.png differ diff --git a/docs/app/assets/img/angular_parts.png b/docs/app/assets/img/angular_parts.png new file mode 100644 index 000000000000..a33a10ba7db5 Binary files /dev/null and b/docs/app/assets/img/angular_parts.png differ diff --git a/docs/app/assets/img/angularjs-for-header-only.svg b/docs/app/assets/img/angularjs-for-header-only.svg new file mode 100644 index 000000000000..68689b6bb1ba --- /dev/null +++ b/docs/app/assets/img/angularjs-for-header-only.svg @@ -0,0 +1,41 @@ + + + +]> + diff --git a/docs/app/assets/img/bullet.png b/docs/app/assets/img/bullet.png new file mode 100755 index 000000000000..3575a8e60f48 Binary files /dev/null and b/docs/app/assets/img/bullet.png differ diff --git a/docs/app/assets/img/form_data_flow.png b/docs/app/assets/img/form_data_flow.png new file mode 100644 index 000000000000..60e947a59583 Binary files /dev/null and b/docs/app/assets/img/form_data_flow.png differ diff --git a/docs/app/assets/img/glyphicons-halflings-white.png b/docs/app/assets/img/glyphicons-halflings-white.png new file mode 100644 index 000000000000..a20760bfde58 Binary files /dev/null and b/docs/app/assets/img/glyphicons-halflings-white.png differ diff --git a/docs/app/assets/img/glyphicons-halflings.png b/docs/app/assets/img/glyphicons-halflings.png new file mode 100644 index 000000000000..92d4445dfd0a Binary files /dev/null and b/docs/app/assets/img/glyphicons-halflings.png differ diff --git a/docs/app/assets/img/guide/concepts-databinding1.png b/docs/app/assets/img/guide/concepts-databinding1.png new file mode 100644 index 000000000000..87b7ffd0bfea Binary files /dev/null and b/docs/app/assets/img/guide/concepts-databinding1.png differ diff --git a/docs/app/assets/img/guide/concepts-databinding2.png b/docs/app/assets/img/guide/concepts-databinding2.png new file mode 100644 index 000000000000..be8cbafe298d Binary files /dev/null and b/docs/app/assets/img/guide/concepts-databinding2.png differ diff --git a/docs/app/assets/img/guide/concepts-directive.png b/docs/app/assets/img/guide/concepts-directive.png new file mode 100644 index 000000000000..b77d5f8ec98e Binary files /dev/null and b/docs/app/assets/img/guide/concepts-directive.png differ diff --git a/docs/app/assets/img/guide/concepts-module-injector.png b/docs/app/assets/img/guide/concepts-module-injector.png new file mode 100644 index 000000000000..31fcf84c626e Binary files /dev/null and b/docs/app/assets/img/guide/concepts-module-injector.png differ diff --git a/docs/app/assets/img/guide/concepts-module-service.png b/docs/app/assets/img/guide/concepts-module-service.png new file mode 100644 index 000000000000..b7580be21b87 Binary files /dev/null and b/docs/app/assets/img/guide/concepts-module-service.png differ diff --git a/docs/app/assets/img/guide/concepts-runtime.png b/docs/app/assets/img/guide/concepts-runtime.png new file mode 100644 index 000000000000..eededc2ab617 Binary files /dev/null and b/docs/app/assets/img/guide/concepts-runtime.png differ diff --git a/docs/app/assets/img/guide/concepts-scope.png b/docs/app/assets/img/guide/concepts-scope.png new file mode 100644 index 000000000000..83ad8f8f4329 Binary files /dev/null and b/docs/app/assets/img/guide/concepts-scope.png differ diff --git a/docs/app/assets/img/guide/concepts-startup.png b/docs/app/assets/img/guide/concepts-startup.png new file mode 100644 index 000000000000..b896a2b51697 Binary files /dev/null and b/docs/app/assets/img/guide/concepts-startup.png differ diff --git a/docs/app/assets/img/guide/concepts-view.png b/docs/app/assets/img/guide/concepts-view.png new file mode 100644 index 000000000000..0222544bee8f Binary files /dev/null and b/docs/app/assets/img/guide/concepts-view.png differ diff --git a/docs/app/assets/img/guide/di_sequence_final.png b/docs/app/assets/img/guide/di_sequence_final.png new file mode 100644 index 000000000000..d4d743bdbc88 Binary files /dev/null and b/docs/app/assets/img/guide/di_sequence_final.png differ diff --git a/docs/app/assets/img/guide/dom_scope_final.png b/docs/app/assets/img/guide/dom_scope_final.png new file mode 100644 index 000000000000..c6385d12ed1f Binary files /dev/null and b/docs/app/assets/img/guide/dom_scope_final.png differ diff --git a/docs/app/assets/img/guide/hashbang_vs_regular_url.jpg b/docs/app/assets/img/guide/hashbang_vs_regular_url.jpg new file mode 100644 index 000000000000..632b4febad28 Binary files /dev/null and b/docs/app/assets/img/guide/hashbang_vs_regular_url.jpg differ diff --git a/docs/app/assets/img/guide/scenario_runner.png b/docs/app/assets/img/guide/scenario_runner.png new file mode 100644 index 000000000000..a39037a0aa38 Binary files /dev/null and b/docs/app/assets/img/guide/scenario_runner.png differ diff --git a/docs/app/assets/img/guide/simple_scope_final.png b/docs/app/assets/img/guide/simple_scope_final.png new file mode 100644 index 000000000000..99a04797a5d4 Binary files /dev/null and b/docs/app/assets/img/guide/simple_scope_final.png differ diff --git a/docs/app/assets/img/helloworld.png b/docs/app/assets/img/helloworld.png new file mode 100644 index 000000000000..957ce8e98b57 Binary files /dev/null and b/docs/app/assets/img/helloworld.png differ diff --git a/docs/app/assets/img/helloworld_2way.png b/docs/app/assets/img/helloworld_2way.png new file mode 100644 index 000000000000..2c02313c1b4a Binary files /dev/null and b/docs/app/assets/img/helloworld_2way.png differ diff --git a/docs/app/assets/img/tutorial/catalog_screen.png b/docs/app/assets/img/tutorial/catalog_screen.png new file mode 100644 index 000000000000..0b1968c5fb28 Binary files /dev/null and b/docs/app/assets/img/tutorial/catalog_screen.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_00.png b/docs/app/assets/img/tutorial/tutorial_00.png new file mode 100644 index 000000000000..65f3973eba00 Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_00.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_00_final.png b/docs/app/assets/img/tutorial/tutorial_00_final.png new file mode 100644 index 000000000000..838a094483e6 Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_00_final.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_02.png b/docs/app/assets/img/tutorial/tutorial_02.png new file mode 100644 index 000000000000..b4c1cab16d95 Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_02.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_03.png b/docs/app/assets/img/tutorial/tutorial_03.png new file mode 100644 index 000000000000..3e432a352e6f Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_03.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_04.png b/docs/app/assets/img/tutorial/tutorial_04.png new file mode 100644 index 000000000000..3d028771dc24 Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_04.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_07_final.png b/docs/app/assets/img/tutorial/tutorial_07_final.png new file mode 100644 index 000000000000..3e7776c4601e Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_07_final.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_08-09_final.png b/docs/app/assets/img/tutorial/tutorial_08-09_final.png new file mode 100644 index 000000000000..02601d241bc7 Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_08-09_final.png differ diff --git a/docs/app/assets/img/tutorial/tutorial_10-11_final.png b/docs/app/assets/img/tutorial/tutorial_10-11_final.png new file mode 100644 index 000000000000..55a821ad188a Binary files /dev/null and b/docs/app/assets/img/tutorial/tutorial_10-11_final.png differ diff --git a/docs/app/assets/img/tutorial/xhr_service_final.png b/docs/app/assets/img/tutorial/xhr_service_final.png new file mode 100644 index 000000000000..b7250e3e3046 Binary files /dev/null and b/docs/app/assets/img/tutorial/xhr_service_final.png differ diff --git a/docs/components/angular-bootstrap/bootstrap-prettify.js b/docs/app/assets/js/angular-bootstrap/bootstrap-prettify.js similarity index 93% rename from docs/components/angular-bootstrap/bootstrap-prettify.js rename to docs/app/assets/js/angular-bootstrap/bootstrap-prettify.js index 5129c4e141e6..e35b4579efbd 100644 --- a/docs/components/angular-bootstrap/bootstrap-prettify.js +++ b/docs/app/assets/js/angular-bootstrap/bootstrap-prettify.js @@ -89,29 +89,6 @@ directive.jsFiddle = function(getEmbeddedTemplate, escape, script) { }; -directive.code = function() { - return {restrict: 'E', terminal: true}; -}; - - -directive.prettyprint = ['reindentCode', function(reindentCode) { - return { - restrict: 'C', - compile: function(element) { - var html = element.html(); - //ensure that angular won't compile {{ curly }} values - html = html.replace(/\{\{/g, '{{') - .replace(/\}\}/g, '}}'); - if (window.RUNNING_IN_NG_TEST_RUNNER) { - element.html(html); - } - else { - element.html(window.prettyPrintOne(reindentCode(html), undefined, true)); - } - } - }; -}]; - directive.ngSetText = ['getEmbeddedTemplate', function(getEmbeddedTemplate) { return { diff --git a/docs/components/angular-bootstrap/bootstrap.js b/docs/app/assets/js/angular-bootstrap/bootstrap.js similarity index 87% rename from docs/components/angular-bootstrap/bootstrap.js rename to docs/app/assets/js/angular-bootstrap/bootstrap.js index b9b5e38278f5..7635216a1051 100644 --- a/docs/components/angular-bootstrap/bootstrap.js +++ b/docs/app/assets/js/angular-bootstrap/bootstrap.js @@ -2,6 +2,56 @@ var directive = {}; +directive.runnableExample = ['$templateCache', '$document', function($templateCache, $document) { + var exampleClassNameSelector = '.runnable-example-file'; + var doc = $document[0]; + var tpl = + ''; + + return { + restrict: 'C', + scope : true, + controller : ['$scope', function($scope) { + $scope.setTab = function(index) { + var tab = $scope.tabs[index]; + $scope.activeTabIndex = index; + $scope.$broadcast('tabChange', index, tab); + }; + }], + compile : function(element) { + element.html(tpl + element.html()); + return function(scope, element) { + var node = element[0]; + var examples = node.querySelectorAll(exampleClassNameSelector); + var tabs = [], now = Date.now(); + angular.forEach(examples, function(child, index) { + tabs.push(child.getAttribute('name')); + }); + + if(tabs.length > 0) { + scope.tabs = tabs; + scope.$on('tabChange', function(e, index, title) { + angular.forEach(examples, function(child) { + child.style.display = 'none'; + }); + var selected = examples[index]; + selected.style.display = 'block'; + }); + scope.setTab(0); + } + } + } + }; +}]; + directive.dropdownToggle = ['$document', '$location', '$window', function ($document, $location, $window) { diff --git a/docs/app/assets/js/angular-bootstrap/dropdown-toggle.js b/docs/app/assets/js/angular-bootstrap/dropdown-toggle.js new file mode 100644 index 000000000000..393b1384ca80 --- /dev/null +++ b/docs/app/assets/js/angular-bootstrap/dropdown-toggle.js @@ -0,0 +1,145 @@ +/* This code is taken from the AngularUI - Bootstrap Project (https://github.com/angular-ui/bootstrap) + * + * The MIT License + * + * Copyright (c) 2012-2014 the AngularUI Team, https://github.com/organizations/angular-ui/teams/291112 + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + */ + +angular.module('ui.bootstrap.dropdown', []) + +.constant('dropdownConfig', { + openClass: 'open' +}) + +.service('dropdownService', ['$document', function($document) { + var self = this, openScope = null; + + this.open = function( dropdownScope ) { + if ( !openScope ) { + $document.bind('click', closeDropdown); + $document.bind('keydown', escapeKeyBind); + } + + if ( openScope && openScope !== dropdownScope ) { + openScope.isOpen = false; + } + + openScope = dropdownScope; + }; + + this.close = function( dropdownScope ) { + if ( openScope === dropdownScope ) { + openScope = null; + $document.unbind('click', closeDropdown); + $document.unbind('keydown', escapeKeyBind); + } + }; + + var closeDropdown = function() { + openScope.$apply(function() { + openScope.isOpen = false; + }); + }; + + var escapeKeyBind = function( evt ) { + if ( evt.which === 27 ) { + closeDropdown(); + } + }; +}]) + +.controller('DropdownController', ['$scope', '$attrs', 'dropdownConfig', 'dropdownService', '$animate', function($scope, $attrs, dropdownConfig, dropdownService, $animate) { + var self = this, openClass = dropdownConfig.openClass; + + this.init = function( element ) { + self.$element = element; + $scope.isOpen = angular.isDefined($attrs.isOpen) ? $scope.$parent.$eval($attrs.isOpen) : false; + }; + + this.toggle = function( open ) { + return $scope.isOpen = arguments.length ? !!open : !$scope.isOpen; + }; + + // Allow other directives to watch status + this.isOpen = function() { + return $scope.isOpen; + }; + + $scope.$watch('isOpen', function( value ) { + $animate[value ? 'addClass' : 'removeClass'](self.$element, openClass); + + if ( value ) { + dropdownService.open( $scope ); + } else { + dropdownService.close( $scope ); + } + + $scope.onToggle({ open: !!value }); + }); + + $scope.$on('$locationChangeSuccess', function() { + $scope.isOpen = false; + }); +}]) + +.directive('dropdown', function() { + return { + restrict: 'CA', + controller: 'DropdownController', + scope: { + isOpen: '=?', + onToggle: '&' + }, + link: function(scope, element, attrs, dropdownCtrl) { + dropdownCtrl.init( element ); + } + }; +}) + +.directive('dropdownToggle', function() { + return { + restrict: 'CA', + require: '?^dropdown', + link: function(scope, element, attrs, dropdownCtrl) { + if ( !dropdownCtrl ) { + return; + } + + element.bind('click', function(event) { + event.preventDefault(); + event.stopPropagation(); + + if ( !element.hasClass('disabled') && !element.prop('disabled') ) { + scope.$apply(function() { + dropdownCtrl.toggle(); + }); + } + }); + + // WAI-ARIA + element.attr({ 'aria-haspopup': true, 'aria-expanded': false }); + scope.$watch(dropdownCtrl.isOpen, function( isOpen ) { + element.attr('aria-expanded', !!isOpen); + }); + } + }; +}); \ No newline at end of file diff --git a/docs/app/src/directives.js b/docs/app/src/directives.js new file mode 100644 index 000000000000..15bef69be43e --- /dev/null +++ b/docs/app/src/directives.js @@ -0,0 +1,35 @@ +angular.module('directives', []) + +.directive('code', function() { + return { restrict:'E', terminal: true }; +}) + +/** + * backToTop Directive + * @param {Function} $anchorScroll + * + * @description Ensure that the browser scrolls when the anchor is clicked + */ +.directive('backToTop', ['$anchorScroll', function($anchorScroll) { + return function link(scope, element) { + element.on('click', function(event) { + scope.$apply($anchorScroll); + }); + }; +}]) + + +.directive('code', function() { + return { + restrict: 'E', + terminal: true, + compile: function(element) { + var linenums = element.hasClass('linenum') || element.parent()[0].nodeName === 'PRE'; + var match = /lang-(\S)+/.exec(element.className); + var lang = match && match[1]; + var html = element.html(); + element.html(window.prettyPrintOne(html, lang, linenums)); + } + }; +}); + diff --git a/docs/app/src/docs.js b/docs/app/src/docs.js new file mode 100644 index 000000000000..fda18e57e0cc --- /dev/null +++ b/docs/app/src/docs.js @@ -0,0 +1,143 @@ +angular.module('docsApp', [ + 'ngRoute', + 'ngCookies', + 'ngSanitize', + 'ngAnimate', + 'versionsData', + 'pagesData', + 'directives', + 'errors', + 'examples', + 'search', + 'tutorials', + 'versions', + 'bootstrap', + 'bootstrapPrettify', + 'ui.bootstrap.dropdown' +]) + + +.config(function($locationProvider) { + $locationProvider.html5Mode(true).hashPrefix('!'); +}) + + +.controller('DocsController', function($scope, $rootScope, $location, $window, $cookies, NG_PAGES, NG_NAVIGATION, NG_VERSION) { + + $scope.fold = function(url) { + if(url) { + $scope.docs_fold = '/notes/' + url; + if(/\/build/.test($window.location.href)) { + $scope.docs_fold = '/build/docs' + $scope.docs_fold; + } + window.scrollTo(0,0); + } + else { + $scope.docs_fold = null; + } + }; + var OFFLINE_COOKIE_NAME = 'ng-offline', + INDEX_PATH = /^(\/|\/index[^\.]*.html)$/; + + + /********************************** + Publish methods + ***********************************/ + + $scope.navClass = function(navItem) { + return { + active: navItem.href && this.currentPage.path, + 'nav-index-section': navItem.type === 'section' + }; + }; + + $scope.afterPartialLoaded = function() { + $window._gaq.push(['_trackPageview', $location.path()]); + }; + + /** stores a cookie that is used by apache to decide which manifest ot send */ + $scope.enableOffline = function() { + //The cookie will be good for one year! + var date = new Date(); + date.setTime(date.getTime()+(365*24*60*60*1000)); + var expires = "; expires="+date.toGMTString(); + var value = angular.version.full; + document.cookie = OFFLINE_COOKIE_NAME + "="+value+expires+"; path=" + $location.path; + + //force the page to reload so server can serve new manifest file + window.location.reload(true); + }; + + + + /********************************** + Watches + ***********************************/ + + + $scope.$watch(function docsPathWatch() {return $location.path(); }, function docsPathWatchAction(path) { + + var currentPage = $scope.currentPage = NG_PAGES[path]; + if ( !currentPage && path.charAt(0)==='/' ) { + // Strip off leading slash + path = path.substr(1); + } + + currentPage = $scope.currentPage = NG_PAGES[path]; + if ( !currentPage && path.charAt(path.length-1) === '/' && path.length > 1 ) { + // Strip off trailing slash + path = path.substr(0, path.length-1); + } + + currentPage = $scope.currentPage = NG_PAGES[path]; + if ( !currentPage && /\/index$/.test(path) ) { + // Strip off index from the end + path = path.substr(0, path.length - 6); + } + + currentPage = $scope.currentPage = NG_PAGES[path]; + + if ( currentPage ) { + $scope.currentArea = currentPage && NG_NAVIGATION[currentPage.area]; + var pathParts = currentPage.path.split('/'); + var breadcrumb = $scope.breadcrumb = []; + var breadcrumbPath = ''; + angular.forEach(pathParts, function(part) { + breadcrumbPath += part; + breadcrumb.push({ name: (NG_PAGES[breadcrumbPath]&&NG_PAGES[breadcrumbPath].name) || part, url: breadcrumbPath }); + breadcrumbPath += '/'; + }); + } else { + $scope.currentArea = null; + $scope.breadcrumb = []; + } + }); + + /********************************** + Initialize + ***********************************/ + + $scope.versionNumber = angular.version.full; + $scope.version = angular.version.full + " " + angular.version.codeName; + $scope.subpage = false; + $scope.offlineEnabled = ($cookies[OFFLINE_COOKIE_NAME] == angular.version.full); + $scope.futurePartialTitle = null; + $scope.loading = 0; + $scope.URL = URL; + $scope.$cookies = $cookies; + + $cookies.platformPreference = $cookies.platformPreference || 'gitUnix'; + + if (!$location.path() || INDEX_PATH.test($location.path())) { + $location.path('/api').replace(); + } + + // bind escape to hash reset callback + angular.element(window).on('keydown', function(e) { + if (e.keyCode === 27) { + $scope.$apply(function() { + $scope.subpage = false; + }); + } + }); +}); diff --git a/docs/app/src/errors.js b/docs/app/src/errors.js new file mode 100644 index 000000000000..b91cfb81493e --- /dev/null +++ b/docs/app/src/errors.js @@ -0,0 +1,62 @@ +angular.module('errors', ['ngSanitize']) + +.filter('errorLink', ['$sanitize', function ($sanitize) { + var LINKY_URL_REGEXP = /((ftp|https?):\/\/|(mailto:)?[A-Za-z0-9._%+-]+@)\S*[^\s\.\;\,\(\)\{\}<>]/g, + MAILTO_REGEXP = /^mailto:/, + STACK_TRACE_REGEXP = /:\d+:\d+$/; + + var truncate = function (text, nchars) { + if (text.length > nchars) { + return text.substr(0, nchars - 3) + '...'; + } + return text; + }; + + return function (text, target) { + var targetHtml = target ? ' target="' + target + '"' : ''; + + if (!text) return text; + + return $sanitize(text.replace(LINKY_URL_REGEXP, function (url) { + if (STACK_TRACE_REGEXP.test(url)) { + return url; + } + + // if we did not match ftp/http/mailto then assume mailto + if (!/^((ftp|https?):\/\/|mailto:)/.test(url)) url = 'mailto:' + url; + + return '' + + truncate(url.replace(MAILTO_REGEXP, ''), 60) + + ''; + })); + }; +}]) + + +.directive('errorDisplay', ['$location', 'errorLinkFilter', function ($location, errorLinkFilter) { + var interpolate = function (formatString) { + var formatArgs = arguments; + return formatString.replace(/\{\d+\}/g, function (match) { + // Drop the braces and use the unary plus to convert to an integer. + // The index will be off by one because of the formatString. + var index = +match.slice(1, -1); + if (index + 1 >= formatArgs.length) { + return match; + } + return formatArgs[index+1]; + }); + }; + + return { + link: function (scope, element, attrs) { + var search = $location.search(), + formatArgs = [attrs.errorDisplay], + i; + + for (i = 0; angular.isDefined(search['p'+i]); i++) { + formatArgs.push(search['p'+i]); + } + element.html(errorLinkFilter(interpolate.apply(null, formatArgs), '_blank')); + } + }; +}]); \ No newline at end of file diff --git a/docs/app/src/examples.js b/docs/app/src/examples.js new file mode 100644 index 000000000000..0ad981c957ea --- /dev/null +++ b/docs/app/src/examples.js @@ -0,0 +1,266 @@ +angular.module('examples', []) + +.directive('sourceEdit', function(getEmbeddedTemplate) { + return { + template: '
+```js var myApp = angular.module('myApp',[]); myApp.controller('MyController', function($scope) { @@ -279,10 +279,10 @@ involves injecting the {@link api/ng.$rootScope $rootScope} and {@link api/ng.$c {"name":"habanero", "spiceness":"LAVA HOT!!"}]; $scope.spice = "habanero"; }); -+``` **Controller Test:** -
+```js describe('myController function', function() { describe('myController', function() { @@ -304,13 +304,13 @@ describe('myController function', function() { }); }); }); -+``` If you need to test a nested Controller you need to create the same scope hierarchy in your test that exists in the DOM: -
+```js describe('state', function() { var mainScope, childScope, grandChildScope; @@ -334,7 +334,7 @@ describe('state', function() { expect(grandChildScope.name).toBe('Gingerbreak Baby'); }); }); -+``` diff --git a/docs/content/guide/dev_guide.e2e-testing.ngdoc b/docs/content/guide/dev_guide.e2e-testing.ngdoc index ce4e586c07d8..b3d3fa94acec 100644 --- a/docs/content/guide/dev_guide.e2e-testing.ngdoc +++ b/docs/content/guide/dev_guide.e2e-testing.ngdoc @@ -1,10 +1,10 @@ @workInProgress @ngdoc overview -@name Developer Guide: E2E Testing +@name E2E Testing @description **Angular Scenario Runner is in maintenance mode - If you're starting a new Angular project, -consider using {@link https://github.com/angular/protractor Protractor}.** +consider using [Protractor](https://github.com/angular/protractor).** @@ -31,7 +31,7 @@ In addition to the above elements, scenarios may also contain helper functions t code in the `it` blocks. Here is an example of a simple scenario: -
+```js describe('Buzz Client', function() { it('should filter results', function() { input('user').enter('jacksparrow'); @@ -41,7 +41,7 @@ it('should filter results', function() { expect(repeater('ul li').count()).toEqual(1); }); }); -+``` Note that [`input('user')`](https://github.com/angular/angular.js/blob/master/docs/content/guide/dev_guide.e2e-testing.ngdoc#L119) @@ -55,7 +55,7 @@ the only button on the page, and then it verifies that there are 10 items listed The API section below lists the available commands and expectations for the Runner. # API -Source: {@link https://github.com/angular/angular.js/blob/master/src/ngScenario/dsl.js} +Source: https://github.com/angular/angular.js/blob/master/src/ngScenario/dsl.js ## pause() Pauses the execution of the tests until you call `resume()` in the console (or click the resume @@ -88,19 +88,19 @@ Returns the window.location.search of the currently loaded page in the test fram Returns the window.location.hash (without `#`) of the currently loaded page in the test frame. ## browser().location().url() -Returns the {@link api/ng.$location $location.url()} of the currently loaded page in +Returns the {@link ng.$location $location.url()} of the currently loaded page in the test frame. ## browser().location().path() -Returns the {@link api/ng.$location $location.path()} of the currently loaded page in +Returns the {@link ng.$location $location.path()} of the currently loaded page in the test frame. ## browser().location().search() -Returns the {@link api/ng.$location $location.search()} of the currently loaded page +Returns the {@link ng.$location $location.search()} of the currently loaded page in the test frame. ## browser().location().hash() -Returns the {@link api/ng.$location $location.hash()} of the currently loaded page in +Returns the {@link ng.$location $location.hash()} of the currently loaded page in the test frame. ## expect(future).{matcher} @@ -188,9 +188,9 @@ Executes the `method` passing in `key` and `value` on the element matching the g Matchers are used in combination with the `expect(...)` function as described above and can be negated with `not()`. For instance: `expect(element('h1').text()).not().toEqual('Error')`. -Source: {@link https://github.com/angular/angular.js/blob/master/src/ngScenario/matchers.js} +Source: https://github.com/angular/angular.js/blob/master/src/ngScenario/matchers.js -
+```js // value and Object comparison following the rules of angular.equals(). expect(value).toEqual(value) @@ -219,10 +219,10 @@ expect(value).toContain(expected) // number comparison using < and > expect(value).toBeLessThan(expected) expect(value).toBeGreaterThan(expected) -+``` # Example -See the {@link https://github.com/angular/angular-seed angular-seed} project for more examples. +See the [angular-seed](https://github.com/angular/angular-seed) project for more examples. ## Conditional actions with element(...).query(fn) @@ -239,7 +239,7 @@ Imagine the application to be structured into two views: 2. a *detail view* which shows the entries' details and contains a delete button. When clicking the delete button, the user is redirected back to the *overview page*. -
+```js beforeEach(function () { var deleteEntry = function () { browser().navigateTo('/entries'); @@ -276,24 +276,24 @@ beforeEach(function () { // start deleting entries deleteEntry(); }); -+``` In order to understand what is happening, we should emphasize that ngScenario calls are not immediately executed, but queued (in ngScenario terms, we would be talking about adding future actions). If we had only one entry in our table, then the following future actions would be queued: -
+```js // delete entry 1 browser().navigateTo('/entries'); element('table tbody').query(function (tbody, done) { ... }); element('table tbody a'); element('.btn-danger').click(); -+``` For two entries, ngScenario would have to work on the following queue: -
+```js // delete entry 1 browser().navigateTo('/entries'); element('table tbody').query(function (tbody, done) { ... }); @@ -306,7 +306,7 @@ element('.btn-danger').click(); element('table tbody').query(function (tbody, done) { ... }); element('table tbody a'); element('.btn-danger').click(); -+``` # Caveats diff --git a/docs/content/guide/dev_guide.services.$location.ngdoc b/docs/content/guide/dev_guide.services.$location.ngdoc index bfd1d5d90999..1d2b0e8206e2 100644 --- a/docs/content/guide/dev_guide.services.$location.ngdoc +++ b/docs/content/guide/dev_guide.services.$location.ngdoc @@ -1,11 +1,10 @@ @ngdoc overview -@name Developer Guide: Angular Services: Using $location +@name Angular Services: Using $location @description # What does it do? -The `$location` service parses the URL in the browser address bar (based on the {@link -https://developer.mozilla.org/en/window.location window.location}) and makes the URL available to +The `$location` service parses the URL in the browser address bar (based on the [window.location](https://developer.mozilla.org/en/window.location)) and makes the URL available to your application. Changes to the URL in the address bar are reflected into $location service and changes to $location are reflected into the browser address bar. @@ -88,7 +87,7 @@ setter methods that allow you to get or change the current URL in the browser. ## $location service configuration To configure the `$location` service, retrieve the -{@link api/ng.$locationProvider $locationProvider} and set the parameters as follows: +{@link ng.$locationProvider $locationProvider} and set the parameters as follows: - **html5Mode(mode)**: {boolean}
+```js $locationProvider.html5Mode(true).hashPrefix('!'); -+``` ## Getter and setter methods `$location` service provides getter methods for read-only parts of the URL (absUrl, protocol, host, port) and getter / setter methods for url, path, search, hash: -
+```js // get the current path $location.path(); // change the path $location.path('/newValue') -+``` All of the setter methods return the same `$location` object to allow chaining. For example, to change multiple segments in one go, chain setters like this: -
$location.path('/newValue').search({key: value});+ +```js +$location.path('/newValue').search({key: value}); +``` ## Replace method @@ -128,14 +130,15 @@ time the $location service is synced with the browser, the last history record s instead of creating a new one. This is useful when you want to implement redirection, which would otherwise break the back button (navigating back would retrigger the redirection). To change the current URL without creating a new browser history record you can call: -
+ +```js $location.path('/someNewPath'); $location.replace(); // or you can chain these as: $location.path('/someNewPath').replace(); -+``` Note that the setters don't update `window.location` immediately. Instead, the `$location` service is -aware of the {@link api/ng.$rootScope.Scope scope} life-cycle and coalesces multiple `$location` +aware of the {@link ng.$rootScope.Scope scope} life-cycle and coalesces multiple `$location` mutations into one "commit" to the `window.location` object during the scope `$digest` phase. Since multiple changes to the $location's state will be pushed to the browser as a single change, it's enough to call the `replace()` method just once to make the entire "commit" a replace operation @@ -145,7 +148,7 @@ unless `replace()` is called again. ### Setters and character encoding You can pass special characters to `$location` service and it will encode them according to rules -specified in {@link http://www.ietf.org/rfc/rfc3986.txt RFC 3986}. When you access the methods: +specified in [RFC 3986](http://www.ietf.org/rfc/rfc3986.txt). When you access the methods: - All values that are passed to `$location` setter methods, `path()`, `search()`, `hash()`, are encoded. @@ -160,7 +163,7 @@ encoded. `$location` service has two configuration modes which control the format of the URL in the browser address bar: **Hashbang mode** (the default) and the **HTML5 mode** which is based on using the -HTML5 {@link http://www.w3.org/TR/html5/history.html History API}. Applications use the same API in +HTML5 [History API](http://www.w3.org/TR/html5/history.html). Applications use the same API in both modes and the `$location` service will work with appropriate URL segments and browser APIs to facilitate the browser URL change and history management. @@ -210,7 +213,7 @@ In this mode, `$location` uses Hashbang URLs in all browsers. ### Example -
+```js it('should show example', inject( function($locationProvider) { $locationProvider.html5Mode(false); @@ -232,18 +235,21 @@ it('should show example', inject( $location.absUrl() == 'http://example.com/base/index.html#!/new?x=y' } )); -+``` ### Crawling your app To allow indexing of your AJAX application, you have to add special meta tag in the head section of your document: - + +```html + +``` This will cause crawler bot to request links with `_escaped_fragment_` param so that your server can recognize the crawler and serve a HTML snapshots. For more information about this technique, -see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX Applications -Crawlable}. +see [Making AJAX Applications +Crawlable](http://code.google.com/web/ajaxcrawling/docs/specification.html). ## HTML5 mode @@ -259,7 +265,7 @@ having to worry about whether the browser displaying your app supports the histo ### Example -
+```js it('should show example', inject( function($locationProvider) { $locationProvider.html5Mode(true); @@ -294,7 +300,7 @@ it('should show example', inject( $location.absUrl() == 'http://example.com/#!/foo/bar?x=y' } )); -+``` ### Fallback for legacy browsers @@ -342,12 +348,15 @@ to entry point of your application (e.g. index.html) If you want your AJAX application to be indexed by web crawlers, you will need to add the following meta tag to the HEAD section of your document: - + +```html + +``` This statement causes a crawler to request links with an empty `_escaped_fragment_` parameter so that your server can recognize the crawler and serve it HTML snapshots. For more information about this -technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX -Applications Crawlable}. +technique, see [Making AJAX +Applications Crawlable](http://code.google.com/web/ajaxcrawling/docs/specification.html). ### Relative links @@ -378,120 +387,116 @@ redirect to regular / hashbang url, as this conversion happens only during parsi = on page reload. In this examples we use `
+```js describe('serviceUnderTest', function() { beforeEach(module(function($provide) { $provide.factory('serviceUnderTest', function($location){ @@ -542,7 +547,7 @@ describe('serviceUnderTest', function() { })); }); -+``` # Migrating from earlier AngularJS releases @@ -625,12 +630,10 @@ then uses the information it obtains to compose hashbang URLs (such as ## Two-way binding to $location -The Angular's compiler currently does not support two-way binding for methods (see {@link -https://github.com/angular/angular.js/issues/404 issue}). If you should require two-way binding -to the $location object (using {@link api/ng.directive:input.text -ngModel} directive on an input field), you will need to specify an extra model property -(e.g. `locationPath`) with two watchers which push $location updates in both directions. For -example: +The Angular's compiler currently does not support two-way binding for methods (see [issue](https://github.com/angular/angular.js/issues/404)). If you should require two-way binding +to the $location object (using {@link input[text] ngModel} directive on an input +field), you will need to specify an extra model property (e.g. `locationPath`) with two watchers +which push $location updates in both directions. For example:
+ +```js var myModule = angular.module('myModule', []); myModule.factory('serviceId', function() { var shinyNewServiceInstance; //factory function body that constructs shinyNewServiceInstance return shinyNewServiceInstance; }); -+``` Using the $provide service: -
+ +```js angular.module('myModule', [], function($provide) { $provide.factory('serviceId', function() { var shinyNewServiceInstance; @@ -40,7 +42,7 @@ angular.module('myModule', [], function($provide) { return shinyNewServiceInstance; }); }); -+``` Note that you are not registering a service instance, but rather a factory function that will create this instance when called. @@ -58,7 +60,7 @@ Following is an example of a very simple service. This service depends on the `$ stores all notifications; after the third one, the service displays all of the notifications by window alert. -
+```js angular.module('myModule', [], function($provide) { $provide.factory('notify', ['$window', function(win) { var msgs = []; @@ -71,7 +73,7 @@ angular.module('myModule', [], function($provide) { }; }]); }); -+``` # Instantiating Angular Services @@ -101,4 +103,4 @@ important. ## Related API -* {@link api/ng Angular Service API} +* {@link ng Angular Service API} diff --git a/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc b/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc index 3dce76721ad7..f3a6dbc9e7b7 100644 --- a/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc +++ b/docs/content/guide/dev_guide.services.injecting_controllers.ngdoc @@ -1,5 +1,5 @@ @ngdoc overview -@name Developer Guide: Angular Services: Injecting Services Into Controllers +@name Angular Services: Injecting Services Into Controllers @description Using services as dependencies for controllers is very similar to using services as dependencies @@ -13,7 +13,7 @@ IDs matters: the order of the services in the array will be used when calling th with injected parameters. The names of parameters in factory function don't matter, but by convention they match the service IDs, which has added benefits discussed below. -
+```js function myController($loc, $log) { this.firstMethod = function() { // use $location service @@ -26,47 +26,48 @@ function myController($loc, $log) { } // which services to inject ? myController.$inject = ['$location', '$log']; -- -
Let's try this simple notify service, injected into the controller...
- - -(you have to click 3 times to see an alert)
-Let's try this simple notify service, injected into the controller...
+ + +(you have to click 3 times to see an alert)
+Let's try the notify service, that is implicitly injected into the controller...
- - -(you have to click 3 times to see an alert)
-Let's try the notify service, that is implicitly injected into the controller...
+ + +(you have to click 3 times to see an alert)
++```js function myModuleCfgFn($provide) { $provide.factory('myService', ['dep1', 'dep2', function(dep1, dep2) {}]); } -+``` Using the $inject property: -
+```js function myModuleCfgFn($provide) { var myServiceFactory = function(dep1, dep2) {}; myServiceFactory.$inject = ['dep1', 'dep2']; $provide.factory('myService', myServiceFactory); } -+``` Using DI inference (incompatible with minifiers): -
+```js function myModuleCfgFn($provide) { $provide.factory('myService', function(dep1, dep2) {}); } -+``` Here is an example of two services, one of which depends on the other and both of which depend on other services that are provided by the Angular framework: -
+```js /** * batchLog service allows for messages to be queued in memory and flushed * to the console.log every 50 seconds. @@ -83,14 +83,14 @@ of which depend on other services that are provided by the Angular framework: // get the main service to kick off the application angular.injector([batchLogModule]).get('routeTemplateMonitor'); -+``` Things to notice in this example: -* The `batchLog` service depends on the built-in {@link api/ng.$interval $interval} and -{@link api/ng.$log $log} services, and allows messages to be logged into the +* The `batchLog` service depends on the built-in {@link ng.$interval $interval} and +{@link ng.$log $log} services, and allows messages to be logged into the `console.log` in batches. -* The `routeTemplateMonitor` service depends on the built-in {@link api/ngRoute.$route +* The `routeTemplateMonitor` service depends on the built-in {@link ngRoute.$route $route} service as well as our custom `batchLog` service. * Both of our services use the factory function signature and array notation for inject annotations to declare their dependencies. It is important that the order of the string identifiers in the array @@ -109,5 +109,5 @@ that the injector uses to determine which services and in which order to inject. ## Related API -* {@link api/ng Angular Service API} -* {@link api/angular.injector Angular Injector API} +* {@link ./ng Angular Service API} +* {@link angular.injector Angular Injector API} diff --git a/docs/content/guide/dev_guide.services.ngdoc b/docs/content/guide/dev_guide.services.ngdoc index 725e01e3eaf4..29eba46f603f 100644 --- a/docs/content/guide/dev_guide.services.ngdoc +++ b/docs/content/guide/dev_guide.services.ngdoc @@ -1,5 +1,5 @@ @ngdoc overview -@name Developer Guide: Angular Services +@name Angular Services @description Services are a feature that Angular brings to client-side web apps from the server side, where @@ -17,4 +17,4 @@ objects that are wired together using {@link di dependency injection (DI)}. ## Related API -* {@link api/ng Angular Service API} +* {@link ./ng Angular Service API} diff --git a/docs/content/guide/dev_guide.services.testing_services.ngdoc b/docs/content/guide/dev_guide.services.testing_services.ngdoc index 6e0bbacebdc6..67a1635d7651 100644 --- a/docs/content/guide/dev_guide.services.testing_services.ngdoc +++ b/docs/content/guide/dev_guide.services.testing_services.ngdoc @@ -1,12 +1,12 @@ @ngdoc overview -@name Developer Guide: Angular Services: Testing Angular Services +@name Angular Services: Testing Angular Services @description The following is a unit test for the 'notify' service in the 'Dependencies' example in {@link dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine spy (mock) instead of a real browser alert. -
+```js var mock, notify; beforeEach(function() { @@ -47,7 +47,7 @@ it('should clear messages after alert', function() { expect(mock.alert.callCount).toEqual(2); expect(mock.alert.mostRecentCall.args).toEqual(["more\ntwo\nthird"]); }); -+``` ## Related Topics @@ -59,4 +59,4 @@ it('should clear messages after alert', function() { ## Related API -* {@link api/ng Angular Service API} +* {@link ./ng Angular Service API} diff --git a/docs/content/guide/dev_guide.services.understanding_services.ngdoc b/docs/content/guide/dev_guide.services.understanding_services.ngdoc index aebd2fa569ef..b17508848568 100644 --- a/docs/content/guide/dev_guide.services.understanding_services.ngdoc +++ b/docs/content/guide/dev_guide.services.understanding_services.ngdoc @@ -1,11 +1,11 @@ @ngdoc overview -@name Developer Guide: Angular Services: Understanding Angular Services +@name Angular Services: Understanding Angular Services @description ## What are Angular Services? Angular services are singletons objects or functions that carry out specific tasks common to web apps. -Angular has a number of built in services, such as the {@link api/ng.$http $http service}, which +Angular has a number of built in services, such as the {@link ng.$http $http service}, which provides access to the browser's `XMLHttpRequest` object for making requests to a server. Like other core Angular variables and identifiers, the built-in services always start with `$` (such as `$http` mentioned above). You can also create your own custom services. @@ -18,7 +18,7 @@ care of the rest. The Angular injector subsystem is in charge of service instant of dependencies, and provision of dependencies to components as requested. Angular injects dependencies using -{@link http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/ "constructor" injection}. +["constructor" injection](http://misko.hevery.com/2009/02/19/constructor-injection-vs-setter-injection/). The dependency is passed to the component's factory/constructor function. Because JavaScript is a dynamically typed language, Angular's dependency injection subsystem cannot use static types to identify service dependencies. For this reason a component must, explicitly, define its dependencies by using one of the @@ -49,12 +49,12 @@ dependent on this service gets a reference to the single instance generated by t ## Related Topics -* {@link di About Angular Dependency Injection} -* {@link dev_guide.services.creating_services Creating Angular Services} -* {@link dev_guide.services.managing_dependencies Managing Service Dependencies} -* {@link dev_guide.services.testing_services Testing Angular Services} +* {@link guide/di About Angular Dependency Injection} +* {@link guide/dev_guide.services.creating_services Creating Angular Services} +* {@link guide/dev_guide.services.managing_dependencies Managing Service Dependencies} +* {@link guide/dev_guide.services.testing_services Testing Angular Services} ## Related API -* {@link api/ng Angular Service API} -* {@link api/angular.injector Injector API} +* {@link ./ng Angular Service API} +* {@link angular.injector Injector API} diff --git a/docs/content/guide/dev_guide.templates.css-styling.ngdoc b/docs/content/guide/dev_guide.templates.css-styling.ngdoc index c00aa9f7709d..b5a3608e45ff 100644 --- a/docs/content/guide/dev_guide.templates.css-styling.ngdoc +++ b/docs/content/guide/dev_guide.templates.css-styling.ngdoc @@ -1,5 +1,5 @@ @ngdoc overview -@name Developer Guide: Templates: Working With CSS in Angular +@name Templates: Working With CSS in Angular @description @@ -8,7 +8,7 @@ Angular sets these CSS classes. It is up to your application to provide useful s # CSS classes used by angular * `ng-scope` - - **Usage:** angular applies this class to any element that where a new {@link api/ng.$rootScope.Scope scope} + - **Usage:** angular applies this class to any element that where a new {@link ng.$rootScope.Scope scope} is defined. (see {@link guide/scope scope} guide for more information about scopes) * `ng-binding` @@ -17,15 +17,15 @@ Angular sets these CSS classes. It is up to your application to provide useful s * `ng-invalid`, `ng-valid` - **Usage:** angular applies this class to an input widget element if that element's input does - not pass validation. (see {@link api/ng.directive:input input} directive) + not pass validation. (see {@link ng.directive:input input} directive) * `ng-pristine`, `ng-dirty` - - **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class + - **Usage:** angular {@link ng.directive:input input} directive applies `ng-pristine` class to a new input widget element which did not have user interaction. Once the user interacts with the input widget the class is changed to `ng-dirty`. ## Related Topics -* {@link templates Angular Templates} -* {@link forms Angular Forms} +* {@link guide/templates Angular Templates} +* {@link guide/forms Angular Forms} diff --git a/docs/content/guide/dev_guide.unit-testing.ngdoc b/docs/content/guide/dev_guide.unit-testing.ngdoc index e73dc2d68e31..2fba61a33a21 100644 --- a/docs/content/guide/dev_guide.unit-testing.ngdoc +++ b/docs/content/guide/dev_guide.unit-testing.ngdoc @@ -1,5 +1,5 @@ @ngdoc overview -@name Developer Guide: Unit Testing +@name Unit Testing @description JavaScript is a dynamically typed language which comes with great power of expression, but it also @@ -52,7 +52,7 @@ While there is nothing wrong with the `new` operator fundamentally, a problem ar on a constructor. This permanently binds the call site to the type. For example, lets say that we try to instantiate an `XHR` that will retrieve data from the server. -
+```js function MyClass() { this.doWork = function() { var xhr = new XHR(); @@ -61,7 +61,7 @@ function MyClass() { xhr.send(); } } -+``` A problem surfaces in tests when we would like to instantiate a `MockXHR` that would allow us to return fake data and simulate network failures. By calling `new XHR()` we are @@ -69,20 +69,21 @@ permanently bound to the actual XHR and there is no way to replace it. Yes, we patch, but that is a bad idea for many reasons which are outside the scope of this document. Here's an example of how the class above becomes hard to test when resorting to monkey patching: -
+ +```js var oldXHR = XHR; XHR = function MockXHR() {}; var myClass = new MyClass(); myClass.doWork(); // assert that MockXHR got called with the right arguments XHR = oldXHR; // if you forget this bad things will happen -+``` ### Global look-up: Another way to approach the problem is to look for the service in a well-known location. -
+```js function MyClass() { this.doWork = function() { global.xhr({ @@ -92,24 +93,24 @@ function MyClass() { }) } } -+``` While no new dependency instance is created, it is fundamentally the same as `new` in that no way exists to intercept the call to `global.xhr` for testing purposes, other then through monkey patching. The basic issue for testing is that a global variable needs to be mutated in -order to replace it with call to a mock method. For further explanation of why this is bad see: {@link -http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/ Brittle Global -State & Singletons} +order to replace it with call to a mock method. For further explanation of why this is bad see: [Brittle Global +State & Singletons](http://misko.hevery.com/code-reviewers-guide/flaw-brittle-global-state-singletons/) The class above is hard to test since we have to change the global state: -
+ +```js var oldXHR = global.xhr; global.xhr = function mockXHR() {}; var myClass = new MyClass(); myClass.doWork(); // assert that mockXHR got called with the right arguments global.xhr = oldXHR; // if you forget this bad things will happen -+``` ### Service Registry: @@ -117,7 +118,7 @@ global.xhr = oldXHR; // if you forget this bad things will happen It may seem that this can be solved by having a registry of all the services and then having the tests replace the services as needed. -
+```js function MyClass() { var serviceRegistry = ????; this.doWork = function() { @@ -128,7 +129,7 @@ function MyClass() { complete:function(response){ ... } }) } -+``` However, where does the serviceRegistry come from? If it is: * `new`-ed up, the test has no chance to reset the services for testing. @@ -136,20 +137,21 @@ However, where does the serviceRegistry come from? If it is: only one global variable exists to be reset). The class above is hard to test since we have to change the global state: -
+ +```js var oldServiceLocator = global.serviceLocator; global.serviceLocator.set('xhr', function mockXHR() {}); var myClass = new MyClass(); myClass.doWork(); // assert that mockXHR got called with the right arguments global.serviceLocator = oldServiceLocator; // if you forget this bad things will happen -+``` ### Passing in Dependencies: Last, the dependency can be passed in. -
+```js function MyClass(xhr) { this.doWork = function() { xhr({ @@ -158,7 +160,7 @@ function MyClass(xhr) { complete:function(response){ ... } }) } -+``` This is the preferred method since the code makes no assumptions about the origin of `xhr` and cares instead about whoever created the class responsible for passing it in. Since the creator of the @@ -166,12 +168,13 @@ class should be different code than the user of the class, it separates the resp creation from the logic. This is dependency-injection in a nutshell. The class above is testable, since in the test we can write: -
+ +```js function xhrMock(args) {...} var myClass = new MyClass(xhrMock); myClass.doWork(); // assert that xhrMock got called with the right arguments -+``` Notice that no global variables were harmed in the writing of this test. @@ -183,7 +186,7 @@ What makes each application unique is its logic, and the logic is what we would for your application contains DOM manipulation, it will be hard to test. See the example below: -
+```js function PasswordCtrl() { // get references to DOM elements var msg = $('.ex1 span'); @@ -206,12 +209,12 @@ function PasswordCtrl() { .text(strength); } } -+``` The code above is problematic from a testability point of view since it requires your test to have the right kind of DOM present when the code executes. The test would look like this: -
+```js
var input = $('');
var span = $('');
$('body').html('')
@@ -223,12 +226,12 @@ input.val('abc');
pc.grade();
expect(span.text()).toEqual('weak');
$('body').empty();
-
+```
In angular the controllers are strictly separated from the DOM manipulation logic and this results in
a much easier testability story as the following example shows:
-
+```js
function PasswordCtrl($scope) {
$scope.password = '';
$scope.grade = function() {
@@ -242,27 +245,27 @@ function PasswordCtrl($scope) {
}
};
}
-
+```
and the test is straight forward:
-
+```js
var $scope = {};
var pc = $controller('PasswordCtrl', { $scope: $scope });
$scope.password = 'abc';
$scope.grade();
expect($scope.strength).toEqual('weak');
-
+```
Notice that the test is not only much shorter, it is also easier to follow what is happening. We say
that such a test tells a story, rather then asserting random bits which don't seem to be related.
## Filters
-{@link api/ng.$filterProvider Filters} are functions which transform the data into a user readable
+{@link ng.$filterProvider Filters} are functions which transform the data into a user readable
format. They are important because they remove the formatting responsibility from the application
logic, further simplifying the application logic.
-
+```js
myModule.filter('length', function() {
return function(text){
return (''+(text||'')).length;
@@ -272,7 +275,7 @@ myModule.filter('length', function() {
var length = $filter('length');
expect(length(null)).toEqual(0);
expect(length('abc')).toEqual(3);
-
+```
## Directives
Directives in angular are responsible for encapsulating complex functionality within custom HTML tags,
@@ -283,13 +286,13 @@ you create with directives may be used throughout your application and in many d
Let's start with an angular app with no dependencies.
-
+```js
var app = angular.module('myApp', []);
-
+```
Now we can add a directive to our app.
-
+```js
app.directive('aGreatEye', function () {
return {
restrict: 'E',
@@ -297,13 +300,13 @@ app.directive('aGreatEye', function () {
template: 'lidless, wreathed in flame, {{1 + 1}} times
'
};
});
-
+```
This directive is used as a tag ` `. It replaces the entire tag with the
template `lidless, wreathed in flame, {{1 + 1}} times
`. Now we are going to write a jasmine unit test to
verify this functionality. Note that the expression `{{1 + 1}}` times will also be evaluated in the rendered content.
-
+```js
describe('Unit testing great quotes', function() {
var $compile;
var $rootScope;
@@ -328,7 +331,7 @@ describe('Unit testing great quotes', function() {
expect(element.html()).toContain("lidless, wreathed in flame, 2 times");
});
});
-
+```
We inject the $compile service and $rootScope before each jasmine test. The $compile service is used
to render the aGreatEye directive. After rendering the directive we ensure that the directive has
@@ -336,5 +339,5 @@ replaced the content and "lidless, wreathed in flame, 2 times" is present.
## Sample project
-See the {@link https://github.com/angular/angular-seed angular-seed} project for an example.
+See the [angular-seed](https://github.com/angular/angular-seed) project for an example.
diff --git a/docs/content/guide/di.ngdoc b/docs/content/guide/di.ngdoc
index b305dd6bcf14..f6d9869129d2 100644
--- a/docs/content/guide/di.ngdoc
+++ b/docs/content/guide/di.ngdoc
@@ -1,5 +1,5 @@
@ngdoc overview
-@name Developer Guide: Dependency Injection
+@name Dependency Injection
@description
# Dependency Injection
@@ -7,10 +7,10 @@
Dependency Injection (DI) is a software design pattern that deals with how code gets hold of its
dependencies.
-For in-depth discussion about DI, see {@link http://en.wikipedia.org/wiki/Dependency_injection
-Dependency Injection} at Wikipedia, {@link http://martinfowler.com/articles/injection.html
-Inversion of Control} by Martin Fowler, or read about DI in your favorite software design pattern
-book.
+For in-depth discussion about DI, see
+[Dependency Injection](http://en.wikipedia.org/wiki/Dependency_injection) at Wikipedia,
+[Inversion of Control](http://martinfowler.com/articles/injection.html) by Martin Fowler,
+or read about DI in your favorite software design pattern book.
## DI in a nutshell
@@ -31,7 +31,7 @@ for test isolation.
The third option is the most viable, since it removes the responsibility of locating the
dependency from the component. The dependency is simply handed to the component.
-
+```js
function SomeClass(greeter) {
this.greeter = greeter;
}
@@ -39,7 +39,7 @@ dependency from the component. The dependency is simply handed to the component.
SomeClass.prototype.doSomething = function(name) {
this.greeter.greet(name);
}
-
+```
In the above example `SomeClass` is not concerned with locating the `greeter` dependency, it
is simply handed the `greeter` at runtime.
@@ -55,7 +55,7 @@ construction and lookup of dependencies.
Here is an example of using the injector service:
-
+```js
// Provide the wiring information in a module
angular.module('myModule', []).
@@ -77,20 +77,20 @@ Here is an example of using the injector service:
// Request any dependency from the injector
var greeter = injector.get('greeter');
-
+```
Asking for dependencies solves the issue of hard coding, but it also means that the injector needs
-to be passed throughout the application. Passing the injector breaks the {@link
-http://en.wikipedia.org/wiki/Law_of_Demeter Law of Demeter}. To remedy this, we turn the
+to be passed throughout the application. Passing the injector breaks the [Law of Demeter](http://en.wikipedia.org/wiki/Law_of_Demeter). To remedy this, we turn the
dependency lookup responsibility to the injector by declaring the dependencies as in this example:
-
+```html
-
-
+```
+
+```js
// And this controller definition
function MyController($scope, greeter) {
$scope.sayHello = function() {
@@ -100,7 +100,7 @@ dependency lookup responsibility to the injector by declaring the dependencies a
// The 'ng-controller' directive does this behind the scenes
injector.instantiate(MyController);
-
+```
Notice that by having the `ng-controller` instantiate the class, it can satisfy all of the
dependencies of `MyController` without the controller ever knowing about the injector. This is
@@ -122,19 +122,18 @@ information. These can be used interchangeably as you see fit and are equivalent
The simplest way to get hold of the dependencies, is to assume that the function parameter names
are the names of the dependencies.
-
+```js
function MyController($scope, greeter) {
...
}
-
+```
Given a function the injector can infer the names of the service to inject by examining the
function declaration and extracting the parameter names. In the above example `$scope`, and
`greeter` are two services which need to be injected into the function.
While straightforward, this method will not work with JavaScript minifiers/obfuscators as they
-rename the method parameter names. This makes this way of annotating only useful for {@link
-http://www.pretotyping.org/ pretotyping}, and demo applications.
+rename the method parameter names. This makes this way of annotating only useful for [pretotyping](http://www.pretotyping.org/), and demo applications.
### `$inject` Annotation
@@ -142,12 +141,12 @@ To allow the minifers to rename the function parameters and still be able to inj
the function needs to be annotated with the `$inject` property. The `$inject` property is an array
of service names to inject.
-
+```js
var MyController = function(renamed$scope, renamedGreeter) {
...
}
MyController['$inject'] = ['$scope', 'greeter'];
-
+```
In this scenario the ordering of the values in the '$inject' array must match the ordering of the arguments to inject.
Using above code snippet as an example, '$scope' will be injected into 'renamed$scope' and 'greeter' into 'renamedGreeter'.
@@ -164,15 +163,15 @@ directives.
For example:
-
+```js
someModule.factory('greeter', function($window) {
...
});
-
+```
Results in code bloat due to needing a temporary variable:
-
+```js
var greeterFactory = function(renamed$window) {
...
};
@@ -180,15 +179,15 @@ Results in code bloat due to needing a temporary variable:
greeterFactory.$inject = ['$window'];
someModule.factory('greeter', greeterFactory);
-
+```
For this reason the third annotation style is provided as well.
-
+```js
someModule.factory('greeter', ['$window', function(renamed$window) {
...
}]);
-
+```
Keep in mind that all of the annotation styles are equivalent and can be used anywhere in Angular
where injection is supported.
@@ -202,7 +201,7 @@ DI is pervasive throughout Angular. It is typically used in controllers and fact
Controllers are classes which are responsible for application behavior. The recommended way of
declaring controllers is using the array notation:
-
+```js
someModule.controller('MyController', ['$scope', 'dep1', 'dep2', function($scope, dep1, dep2) {
...
$scope.aMethod = function() {
@@ -210,7 +209,7 @@ declaring controllers is using the array notation:
}
...
}]);
-
+```
This avoids the creation of global functions for controllers and also protects against minification.
@@ -221,7 +220,7 @@ Factory methods are responsible for creating most objects in Angular. Examples a
services, and filters. The factory methods are registered with the module, and the recommended way
of declaring factories is:
-
+```js
angular.module('myModule', []).
config(['depProvider', function(depProvider){
...
@@ -238,4 +237,4 @@ of declaring factories is:
run(['depService', function(depService) {
...
}]);
-
+```
diff --git a/docs/content/guide/directive.ngdoc b/docs/content/guide/directive.ngdoc
index 704dd48357c5..6c81419a33a1 100644
--- a/docs/content/guide/directive.ngdoc
+++ b/docs/content/guide/directive.ngdoc
@@ -7,7 +7,7 @@
**Note:** this guide is targeted towards developers who are already familiar with AngularJS basics.
If you're just getting started, we recommend the {@link tutorial/ tutorial} first.
-If you're looking for the **directives API**, we recently moved it to {@link api/ng.$compile `$compile`}.
+If you're looking for the **directives API**, we recently moved it to {@link ng.$compile `$compile`}.
@@ -18,7 +18,7 @@ how to implement them.
## What are Directives?
At a high level, directives are markers on a DOM element (such as an attribute, element
-name, or CSS class) that tell AngularJS's **HTML compiler** ({@link api/ng.$compile `$compile`}) to
+name, or CSS class) that tell AngularJS's **HTML compiler** ({@link ng.$compile `$compile`}) to
attach a specified behavior to that DOM element or even transform the DOM element and its children.
Angular comes with a set of these directives built-in, like `ngBind`, `ngModel`, and `ngView`.
@@ -32,7 +32,7 @@ When Angular {@link guide/bootstrap bootstraps} your application, the
For AngularJS, "compilation" means attaching event listeners to the HTML to make it interactive.
The reason we use the term "compile" is that the recursive process of attaching directives
mirrors the process of compiling source code in
-{@link http://en.wikipedia.org/wiki/Compiled_languages compiled programming languages}.
+[compiled programming languages](http://en.wikipedia.org/wiki/Compiled_languages).
@@ -55,9 +55,9 @@ The following also **matches** `ngModel`:
Angular **normalizes** an element's tag and attribute name to determine which elements match which
directives. We typically refer to directives by their case-sensitive
-{@link http://en.wikipedia.org/wiki/CamelCase camelCase} **normalized** name (e.g. `ngModel`).
+[camelCase](http://en.wikipedia.org/wiki/CamelCase) **normalized** name (e.g. `ngModel`).
However, since HTML is case-insensitive, we refer to directives in the DOM by lower-case
-forms, typically using {@link http://en.wikipedia.org/wiki/Letter_case#Computers dash-delimited}
+forms, typically using [dash-delimited](http://en.wikipedia.org/wiki/Letter_case#Computers)
attributes on DOM elements (e.g. `ng-model`).
The **normalization** process is as follows:
@@ -120,7 +120,7 @@ Doing so generally makes it easier to determine what directives a given element
**Best Practice:** Comment directives were commonly used in places where the DOM API limits the
ability to create directives that spanned multiple elements (e.g. inside `` elements).
-AngularJS 1.2 introduces {@link api/ng.directive:ngRepeat `ng-repeat-start` and `ng-repeat-end`}
+AngularJS 1.2 introduces {@link ng.directive:ngRepeat `ng-repeat-start` and `ng-repeat-end`}
as a better solution to this problem. Developers are encouraged to use this over custom comment
directives when possible.
@@ -129,10 +129,10 @@ directives when possible.
### Text and attribute bindings
-During the compilation process the {@link api/ng.$compile compiler} matches text and attributes
-using the {@link api/ng.$interpolate $interpolate} service to see if they contain embedded
-expressions. These expressions are registered as {@link api/ng.$rootScope.Scope#methods_$watch watches}
-and will update as part of normal {@link api/ng.$rootScope.Scope#methods_$digest digest} cycle. An
+During the compilation process the {@link ng.$compile compiler} matches text and attributes
+using the {@link ng.$interpolate $interpolate} service to see if they contain embedded
+expressions. These expressions are registered as {@link ng.$rootScope.Scope#methods_$watch watches}
+and will update as part of normal {@link ng.$rootScope.Scope#methods_$digest digest} cycle. An
example of interpolation is shown below:
```html
@@ -174,7 +174,7 @@ For example, we could fix the example above by instead writing:
## Creating Directives
-First let's talk about the {@link api/ng.$compileProvider#methods_directive API for registering directives}. Much like
+First let's talk about the {@link ng.$compileProvider#methods_directive API for registering directives}. Much like
controllers, directives are registered on modules. To register a directive, you use the
`module.directive` API. `module.directive` takes the
{@link guide/directive#creating-custom-directives_matching-directives normalized} directive name
@@ -183,9 +183,9 @@ options to tell `$compile` how the directive should behave when matched.
The factory function is invoked only once when the
-{@link api/ng.$compile compiler} matches the directive for the first time. You can perform any
+{@link ng.$compile compiler} matches the directive for the first time. You can perform any
initialization work here. The function is invoked using
-{@link api/AUTO.$injector#methods_invoke $injector.invoke} which makes it injectable just like a
+{@link auto.$injector#methods_invoke $injector.invoke} which makes it injectable just like a
controller.
@@ -324,9 +324,9 @@ Let's change our directive to use `restrict: 'E'`:
For more on the
-{@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object `restrict`}
+{@link ng.$compile#description_comprehensive-directive-api_directive-definition-object `restrict`}
property, see the
-{@link api/ng.$compile#description_comprehensive-directive-api_directive-definition-object API docs}.
+{@link ng.$compile#description_comprehensive-directive-api_directive-definition-object API docs}.
**When should I use an attribute versus an element?**
@@ -791,7 +791,7 @@ element?
$document.unbind('mousemove', mousemove);
$document.unbind('mouseup', mouseup);
}
- }
+ };
});
@@ -829,7 +829,7 @@ to which tab is active.
};
this.addPane = function(pane) {
- if (panes.length == 0) {
+ if (panes.length === 0) {
$scope.select(pane);
}
panes.push(pane);
@@ -912,6 +912,6 @@ point for creating your own directives.
You might also be interested in an in-depth explanation of the compilation process that's
available in the {@link guide/compiler compiler guide}.
-The {@link api/ng.$compile `$compile` API} page has a comprehensive list of directive options for
+The {@link ng.$compile `$compile` API} page has a comprehensive list of directive options for
reference.
diff --git a/docs/content/guide/expression.ngdoc b/docs/content/guide/expression.ngdoc
index 99cc7514578e..5aa0523641d9 100644
--- a/docs/content/guide/expression.ngdoc
+++ b/docs/content/guide/expression.ngdoc
@@ -1,10 +1,10 @@
@ngdoc overview
-@name Developer Guide: Expressions
+@name Expressions
@description
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
-expression }}`. Expressions are processed by the {@link api/ng.$parse $parse}
-service. Expressions are often post processed using {@link filter filters} to create a more user-friendly format.
+expression }}`. Expressions are processed by the {@link ng.$parse $parse}
+service. Expressions are often post processed using {@link guide/filter filters} to create a more user-friendly format.
For example, these are all valid expressions in angular:
@@ -30,100 +30,105 @@ You can think of Angular expressions as JavaScript expressions with following di
If, on the other hand, you do want to run arbitrary JavaScript code, you should make it a
controller method and call the method. If you want to `eval()` an angular expression from
-JavaScript, use the {@link api/ng.$rootScope.Scope#methods_$eval `$eval()`} method.
+JavaScript, use the {@link ng.$rootScope.Scope#methods_$eval `$eval()`} method.
## Example
-
-
- 1+2={{1+2}}
-
-
- it('should calculate expression in binding', function() {
- expect(element(by.binding('1+2')).getText()).toEqual('1+2=3');
- });
-
-
+
+
+ 1+2={{1+2}}
+
+
+
+ it('should calculate expression in binding', function() {
+ expect(element(by.binding('1+2')).getText()).toEqual('1+2=3');
+ });
+
+
You can try evaluating different expressions here:
-
-
-
-
- Expression:
-
-
-
- -
- [ X ]
- {{expr}} =>
-
-
-
-
-
- it('should allow user expression testing', function() {
- element(by.css('.expressions button')).click();
- var lis = element(by.css('.expressions ul')).element.all(by.repeater('expr in exprs'));
- expect(lis.count()).toBe(1);
- expect(lis.get(0).getText()).toEqual('[ X ] 3*10|currency => $30.00');
- });
-
-
+ };
+
+ $scope.removeExp = function(index) {
+ exprs.splice(index, 1);
+ };
+ }
+
+
+
+ it('should allow user expression testing', function() {
+ element(by.css('.expressions button')).click();
+ var lis = element(by.css('.expressions ul')).element.all(by.repeater('expr in exprs'));
+ expect(lis.count()).toBe(1);
+ expect(lis.get(0).getText()).toEqual('[ X ] 3*10|currency => $30.00');
+ });
+
+
# Property Evaluation
Evaluation of all properties takes place against a scope. Unlike JavaScript, where names default
-to global window properties, Angular expressions have to use {@link api/ng.$window
+to global window properties, Angular expressions have to use {@link ng.$window
`$window`} to refer to the global `window` object. For example, if you want to call `alert()`, which is
defined on `window`, in an expression you must use `$window.alert()`. This is done intentionally to
prevent accidental access to the global state (a common source of subtle bugs).
-
-
-
-
- Name:
-
-
-
-
- it('should calculate expression in binding', function() {
- if (browser.params.browser = 'safari') {
- // Safari can't handle dialogs.
- return;
- };
- element(by.css('[ng-click="greet()"]')).click();
-
- var alertDialog = browser.switchTo().alert();
-
- expect(alertDialog.getText()).toEqual('Hello World');
-
- alertDialog.accept();
- });
-
-
+
+
+
+ Name:
+
+
+
+
+
+ function Cntl1($window, $scope){
+ $scope.name = 'World';
+
+ $scope.greet = function() {
+ $window.alert('Hello ' + $scope.name);
+ };
+ }
+
+
+
+ it('should calculate expression in binding', function() {
+ if (browser.params.browser == 'safari') {
+ // Safari can't handle dialogs.
+ return;
+ }
+ element(by.css('[ng-click="greet()"]')).click();
+
+ var alertDialog = browser.switchTo().alert();
+
+ expect(alertDialog.getText()).toEqual('Hello World');
+
+ alertDialog.accept();
+ });
+
+
## Forgiving
diff --git a/docs/content/guide/filter.ngdoc b/docs/content/guide/filter.ngdoc
index 30e488339da4..a3b43ac7bd7a 100644
--- a/docs/content/guide/filter.ngdoc
+++ b/docs/content/guide/filter.ngdoc
@@ -5,7 +5,7 @@
A filter formats the value of an expression for display to the user. They can be used in view templates,
controllers or services and it is easy to define your own filter.
-The underlying API is the {@link api/ng.$filterProvider filterProvider}.
+The underlying API is the {@link ng.$filterProvider filterProvider}.
## Using filters in view templates
@@ -13,7 +13,7 @@ Filters can be applied to expressions in view templates using the following synt
{{ expression | filter }}
-E.g. the markup `{{ 12 | currency }}` formats the number 12 as a currency using the {@link api/ng.filter:currency `currency`}
+E.g. the markup `{{ 12 | currency }}` formats the number 12 as a currency using the {@link ng.filter:currency `currency`}
filter. The resulting value is `$12.00`.
Filters can be applied to the result of another filter. This is called "chaining" and uses
@@ -26,7 +26,7 @@ Filters may have arguments. The syntax for this is
{{ expression | filter:argument1:argument2:... }}
E.g. the markup `{{ 1234 | number:2 }}` formats the number 1234 with 2 decimal points using the
-{@link api/ng.filter:number `number`} filter. The resulting value is `1,234.00`.
+{@link ng.filter:number `number`} filter. The resulting value is `1,234.00`.
## Using filters in controllers and services
@@ -36,7 +36,7 @@ to your controller or service. E.g. using the dependency `numberFilter` will inj
The injected argument is a function that takes the value to format as first argument and filter parameters
starting with the second argument.
-The example below uses the filter called {@link api/ng.filter:filter `filter`}.
+The example below uses the filter called {@link ng.filter:filter `filter`}.
This filter reduces arrays into sub arrays based on
conditions. The filter can be applied in the view template with markup like
`{{ctrl.array | filter:'a'}}`, which would do a fulltext search for "a".
@@ -47,41 +47,41 @@ The example below therefore calls the filter directly in the controller.
By this, the controller is able to call the filter only when needed (e.g. when the data is loaded from the backend
or the filter expression is changed).
-
-
-
-
-
-
- All entries:
- {{entry.name}}
-
-
- Entries that contain an "a":
- {{entry.name}}
-
-
-
-
+
+
+
+
+ All entries:
+ {{entry.name}}
+
+
+ Entries that contain an "a":
+ {{entry.name}}
+
+
+
+
+
+ angular.module('FilterInControllerModule', []).
+ controller('FilterController', ['filterFilter', function(filterFilter) {
+ this.array = [
+ {name: 'Tobias'},
+ {name: 'Jeff'},
+ {name: 'Brian'},
+ {name: 'Igor'},
+ {name: 'James'},
+ {name: 'Brad'}
+ ];
+ this.filteredArray = filterFilter(this.array, 'a');
+ }]);
+
+
## Creating custom filters
Writing your own filter is very easy: just register a new filter factory function with
-your module. Internally, this uses the {@link api/ng.$filterProvider `filterProvider`}.
+your module. Internally, this uses the {@link ng.$filterProvider `filterProvider`}.
This factory function should return a new filter function which takes the input value
as the first argument. Any filter arguments are passed in as additional arguments to the filter
function.
@@ -89,38 +89,38 @@ function.
The following sample filter reverses a text string. In addition, it conditionally makes the
text upper-case.
-
-
-
-
-
-
- No filter: {{greeting}}
- Reverse: {{greeting|reverse}}
- Reverse + uppercase: {{greeting|reverse:true}}
-
-
-
+
+
+
+
+ No filter: {{greeting}}
+ Reverse: {{greeting|reverse}}
+ Reverse + uppercase: {{greeting|reverse:true}}
+
+
+
+
+ angular.module('MyReverseModule', []).
+ filter('reverse', function() {
+ return function(input, uppercase) {
+ var out = "";
+ for (var i = 0; i < input.length; i++) {
+ out = input.charAt(i) + out;
+ }
+ // conditional based on optional argument
+ if (uppercase) {
+ out = out.toUpperCase();
+ }
+ return out;
+ };
+ });
+
+ function Ctrl($scope) {
+ $scope.greeting = 'hello';
+ }
+
+
## Testing custom filters
-See the {@link http://docs.angularjs.org/tutorial/step_09#test phonecat tutorial} for an example.
+See the [phonecat tutorial](http://docs.angularjs.org/tutorial/step_09#test) for an example.
diff --git a/docs/content/guide/forms.ngdoc b/docs/content/guide/forms.ngdoc
index 84ee4330c945..8a23c8c820bd 100644
--- a/docs/content/guide/forms.ngdoc
+++ b/docs/content/guide/forms.ngdoc
@@ -12,42 +12,42 @@ Server-side validation is still necessary for a secure application.
# Simple form
-The key directive in understanding two-way data-binding is {@link api/ng.directive:ngModel ngModel}.
+The key directive in understanding two-way data-binding is {@link ng.directive:ngModel ngModel}.
The `ngModel` directive provides the two-way data-binding by synchronizing the model to the view, as well as view to the model.
-In addition it provides an {@link api/ng.directive:ngModel.NgModelController API} for other directives to augment its behavior.
-
-
-
-
-
- form = {{user | json}}
- master = {{master | json}}
-
-
-
-
-
+In addition it provides an {@link ngModel.NgModelController API} for other directives to augment its behavior.
+
+
+
+
+
+ form = {{user | json}}
+ master = {{master | json}}
+
+
+
+
+
Note that `novalidate` is used to disable browser's native form validation.
@@ -67,57 +67,57 @@ The following example uses the CSS to display validity of each form control.
In the example both `user.name` and `user.email` are required, but are rendered with red background only when they are dirty.
This ensures that the user is not distracted with an error until after interacting with the control, and failing to satisfy its validity.
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
# Binding to form and control state
-A form is an instance of {@link api/ng.directive:form.FormController FormController}.
+A form is an instance of {@link form.FormController FormController}.
The form instance can optionally be published into the scope using the `name` attribute.
-Similarly, an input control that has the {@link api/ng.directive:ngModel ngModel} directive holds an
-instance of {@link api/ng.directive:ngModel.NgModelController NgModelController}.
+Similarly, an input control that has the {@link ng.directive:ngModel ngModel} directive holds an
+instance of {@link ngModel.NgModelController NgModelController}.
Such a control instance can be published as a property of the form instance using the `name` attribute
on the input control. The name attribute specifies the name of the property on the form instance.
@@ -130,72 +130,72 @@ This allows us to extend the above example with these features:
- SAVE button is enabled only if form has some changes and is valid
- custom error messages for `user.email` and `user.agree`
-
-
-
-