Compare commits
71 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da984ad187 | ||
|
|
4015357ce5 | ||
|
|
dc3d11ad19 | ||
|
|
0e1545eb04 | ||
|
|
ec7cabf5c9 | ||
|
|
3051beba2f | ||
|
|
92304323b1 | ||
|
|
c28123a872 | ||
|
|
d798423813 | ||
|
|
2583e77cc7 | ||
|
|
f66836fee4 | ||
|
|
0ccc445d53 | ||
|
|
b7d5fa1cbe | ||
|
|
8bb3942453 | ||
|
|
51a79cebcb | ||
|
|
36bcf64008 | ||
|
|
5c6630605b | ||
|
|
125827406c | ||
|
|
62c21422a6 | ||
|
|
98d489712e | ||
|
|
2cab2d8ef1 | ||
|
|
8fa2bb72bc | ||
|
|
d151f94937 | ||
|
|
5b74b7185b | ||
|
|
4f0be2ae4e | ||
|
|
bb9badeb2a | ||
|
|
c287c8361d | ||
|
|
ade7127c79 | ||
|
|
d341483f1f | ||
|
|
b36acbc857 | ||
|
|
a4fea38b94 | ||
|
|
300c5c0c99 | ||
|
|
152537c4e9 | ||
|
|
8b46bf6bc9 | ||
|
|
aef861eb41 | ||
|
|
f61d36861d | ||
|
|
2af0348cea | ||
|
|
78c5743494 | ||
|
|
2cb9fbd043 | ||
|
|
e9dad5dbf4 | ||
|
|
54895fc2a1 | ||
|
|
60a12b4161 | ||
|
|
cd7e58ba41 | ||
|
|
9391475dc3 | ||
|
|
7840803add | ||
|
|
7d77de2834 | ||
|
|
ab044cada6 | ||
|
|
d010e0cc7d | ||
|
|
40f728b1aa | ||
|
|
23abb26405 | ||
|
|
fd55bc8e1d | ||
|
|
541aaa4e08 | ||
|
|
f22c422547 | ||
|
|
0e461f0c07 | ||
|
|
5074448443 | ||
|
|
8d66af11e6 | ||
|
|
169948bb47 | ||
|
|
58d9469574 | ||
|
|
8d858a2360 | ||
|
|
5540748890 | ||
|
|
f8a52be817 | ||
|
|
3b5f1105f6 | ||
|
|
663ccc5449 | ||
|
|
263f47819f | ||
|
|
6b75475ce3 | ||
|
|
07c354a8c0 | ||
|
|
1391579599 | ||
|
|
5d2bd1d84c | ||
|
|
bf77e212af | ||
|
|
eef2f9c31e | ||
|
|
438627c2c3 |
14
.gitattributes
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# Auto detect text files and perform LF normalization
|
||||||
|
* text=auto
|
||||||
|
|
||||||
|
# Standard to msysgit
|
||||||
|
*.doc diff=astextplain
|
||||||
|
*.DOC diff=astextplain
|
||||||
|
*.docx diff=astextplain
|
||||||
|
*.DOCX diff=astextplain
|
||||||
|
*.dot diff=astextplain
|
||||||
|
*.DOT diff=astextplain
|
||||||
|
*.pdf diff=astextplain
|
||||||
|
*.PDF diff=astextplain
|
||||||
|
*.rtf diff=astextplain
|
||||||
|
*.RTF diff=astextplain
|
||||||
97
CHANGELOG.md
|
|
@ -1,3 +1,100 @@
|
||||||
|
<a name="1.1.0"></a>
|
||||||
|
# 1.1.0 increase-gravatas (2012-08-31)
|
||||||
|
|
||||||
|
_Note: 1.1.x releases unlike 1.0.x are considered unstable.
|
||||||
|
[More info](http://blog.angularjs.org/2012/07/angularjs-10-12-roadmap.html)_
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **$http:** support custom reponseType
|
||||||
|
([e0a54f6b](https://github.com/angular/angular.js/commit/e0a54f6b206dc2b6595f2bc3a17c5932e7477545),
|
||||||
|
[#1013](https://github.com/angular/angular.js/issues/1013))
|
||||||
|
- **$interpolate:**
|
||||||
|
- provide contextual error messages
|
||||||
|
([d804bbcd](https://github.com/angular/angular.js/commit/d804bbcd51ec83bee1f4a3ccd42c3bd7eb38a988))
|
||||||
|
- expose start/end symbols in run phase
|
||||||
|
([58f121a5](https://github.com/angular/angular.js/commit/58f121a5c293ed57043e22ed526fdf99642fca81))
|
||||||
|
- **$sniffer:** auto detect CSP mode (currently requires Chrome on dev channel)
|
||||||
|
([167aa0c2](https://github.com/angular/angular.js/commit/167aa0c29c998be33c49d33302e099b36d1ce0be))
|
||||||
|
|
||||||
|
This release also contains all bug fixes available in [1.0.2](#1.0.2).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="1.0.2"></a>
|
||||||
|
# 1.0.2 debilitating-awesomeness (2012-08-31)
|
||||||
|
|
||||||
|
|
||||||
|
## Bug Fixes
|
||||||
|
|
||||||
|
- **$compile:** denormalize directive templates
|
||||||
|
([dfe99836](https://github.com/angular/angular.js/commit/dfe99836cd98c2a1b0f9bde6216bd44088de275a))
|
||||||
|
- **$interpolate:** $interpolateProvider.endSymbol() returns startSymbol
|
||||||
|
([20348717](https://github.com/angular/angular.js/commit/20348717640c0ef405c9fdcc8fec5b566efc48b3))
|
||||||
|
- **jqLite:** better support for xhtml
|
||||||
|
([d3fa7a2e](https://github.com/angular/angular.js/commit/d3fa7a2e9e93c9dae13d852b28c878f7d6b7c420),
|
||||||
|
[#1301](https://github.com/angular/angular.js/issues/1301))
|
||||||
|
- **mocks:** free up memory after every spec
|
||||||
|
([1a8642aa](https://github.com/angular/angular.js/commit/1a8642aac2de40dccdab464e58dc164006c300bb))
|
||||||
|
- **e2e test runner:** Adding meta tag to avoid cache issues
|
||||||
|
([5318588d](https://github.com/angular/angular.js/commit/5318588d6e8ee9a31f4002affd6858d25305aabf))
|
||||||
|
- Directives:
|
||||||
|
- **form:** prevent page reload when form destroyed
|
||||||
|
([054d40f3](https://github.com/angular/angular.js/commit/054d40f338f9000cddcf7f0513af37328b88ef41),
|
||||||
|
[#1238](https://github.com/angular/angular.js/issues/1238))
|
||||||
|
- **ngList:** remove data bound flicker
|
||||||
|
([fa62ea81](https://github.com/angular/angular.js/commit/fa62ea810f6c701e898dd07c6c9228f13d5b5e02))
|
||||||
|
- **ngPluralize:** fixes ng-pluralize when using non-standard start/end symbols
|
||||||
|
([e85774f7](https://github.com/angular/angular.js/commit/e85774f709b9f681b0ff8d829b07568b0f844a62),
|
||||||
|
[#1134](https://github.com/angular/angular.js/issues/1134))
|
||||||
|
- **option:** support option elements in datalist
|
||||||
|
([9767f7bd](https://github.com/angular/angular.js/commit/9767f7bdd3e1ce6f65bdea992d67369ead13d813),
|
||||||
|
[#1165](https://github.com/angular/angular.js/issues/1165))
|
||||||
|
|
||||||
|
|
||||||
|
## Docs
|
||||||
|
|
||||||
|
- Conceptual Overview of AngularJS (high level overview of how things work):
|
||||||
|
<http://docs.angularjs.org/guide/concepts>
|
||||||
|
([7a5f25f6](https://github.com/angular/angular.js/commit/7a5f25f6671eb5f51b06615d74a05855ab79f31e))
|
||||||
|
- Lots of spelling, grammar and other fixes:
|
||||||
|
[9a710c78](https://github.com/angular/angular.js/commit/9a710c788d880785d2b02a9c5411eb15e9c278bf),
|
||||||
|
[847d2da0](https://github.com/angular/angular.js/commit/847d2da0f8d1e265eda7b4dd3e7eb52ac86d784e),
|
||||||
|
[dbefd671](https://github.com/angular/angular.js/commit/dbefd671e41c3bda481850bb7e566349e275d759),
|
||||||
|
[cab5e1d9](https://github.com/angular/angular.js/commit/cab5e1d9b363eac6fd31b15c5b86f30993e2f147),
|
||||||
|
[f00b6cca](https://github.com/angular/angular.js/commit/f00b6cca024a9418f353651f29c984f934575bd9),
|
||||||
|
[2e365168](https://github.com/angular/angular.js/commit/2e3651686c2bd84cf464ecc236c8ad77e61179df),
|
||||||
|
[536de148](https://github.com/angular/angular.js/commit/536de148214290f0b4a0595fa16c00da5e527e79),
|
||||||
|
[a1107e81](https://github.com/angular/angular.js/commit/a1107e81ebf2254caf75718de2e3ec773cce0c56),
|
||||||
|
[5ef9ed87](https://github.com/angular/angular.js/commit/5ef9ed87d82b109715a87e9aa1b1d5b63f515d3a),
|
||||||
|
[8c81a0f3](https://github.com/angular/angular.js/commit/8c81a0f3728b9308854ceb9bf392ec467b95d8eb),
|
||||||
|
[bde931af](https://github.com/angular/angular.js/commit/bde931afd5cf2483df236e06992666a0a4182794),
|
||||||
|
[6553fe68](https://github.com/angular/angular.js/commit/6553fe68d17d42ec25e0c592ceaa1077cc0ec4f6),
|
||||||
|
[13b5fd1b](https://github.com/angular/angular.js/commit/13b5fd1b9d60f1a9187da8a89db9272284ccdac4),
|
||||||
|
[17209d5b](https://github.com/angular/angular.js/commit/17209d5b4a579edf8425715b5cdf25bc5cd96711),
|
||||||
|
[31c82560](https://github.com/angular/angular.js/commit/31c825607dd524241c811ca3e401b119c810e977),
|
||||||
|
[ab6937e2](https://github.com/angular/angular.js/commit/ab6937e2518bfd77d9fe42e3d2e11fe4a7a16814),
|
||||||
|
[fbfda241](https://github.com/angular/angular.js/commit/fbfda241f616bcfe8273f501dd49120a3cb35fab),
|
||||||
|
[206371b7](https://github.com/angular/angular.js/commit/206371b7372c242db234ca8da12d1c7a8a322d54),
|
||||||
|
[b6b92bd8](https://github.com/angular/angular.js/commit/b6b92bd866e1d6d066f1c9bf1937496cd3e28664),
|
||||||
|
[79f2d843](https://github.com/angular/angular.js/commit/79f2d843a8458bfdc23fe9f179a1416fe21f7533),
|
||||||
|
[64a9cd8f](https://github.com/angular/angular.js/commit/64a9cd8f4fac1c518869a1c955fe60bd6ef76439),
|
||||||
|
[7f6e1326](https://github.com/angular/angular.js/commit/7f6e1326f3a7a6a2ba2dbd48dd6571ebe929a7c1),
|
||||||
|
[1fd2b3d4](https://github.com/angular/angular.js/commit/1fd2b3d402f36e395a1fe9ea7e3f91a1b2833426),
|
||||||
|
[d56d69cc](https://github.com/angular/angular.js/commit/d56d69cc8319f69135a17a9bb5ae394123b33c51),
|
||||||
|
[01e726b2](https://github.com/angular/angular.js/commit/01e726b2fa3fb0d2584c9bb8df116ff3a9f05879),
|
||||||
|
[16136216](https://github.com/angular/angular.js/commit/161362164532af3578c9e3e8b52cd80b15345add),
|
||||||
|
[92a3d282](https://github.com/angular/angular.js/commit/92a3d2821856c75eb95f8ec6ccf26d6a9b37fdd9),
|
||||||
|
[4c585019](https://github.com/angular/angular.js/commit/4c5850195699b1d982963f25399d24bf8b815f81),
|
||||||
|
[c076fe08](https://github.com/angular/angular.js/commit/c076fe08cf47e8af4b5e8845aed917ebb7dbd593),
|
||||||
|
[2473412b](https://github.com/angular/angular.js/commit/2473412ba55f7c47f2ca24311312ce95ee11949e),
|
||||||
|
[1f2d5000](https://github.com/angular/angular.js/commit/1f2d50000e82630bfce6eb9cf0a8da752fd1e826),
|
||||||
|
[5026315d](https://github.com/angular/angular.js/commit/5026315d6f4495d636d86ae2a022fb55cc0ca211),
|
||||||
|
[f0a090dd](https://github.com/angular/angular.js/commit/f0a090ddf256d0c144e705c0cdf4216d824140f9),
|
||||||
|
[6d9313a6](https://github.com/angular/angular.js/commit/6d9313a68d82654d389c0b2c3e4af148382f14be)) and more!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<a name="1.0.1"></a>
|
<a name="1.0.1"></a>
|
||||||
# 1.0.1 thorium-shielding (2012-06-25)
|
# 1.0.1 thorium-shielding (2012-06-25)
|
||||||
|
|
||||||
|
|
|
||||||
148
Rakefile
|
|
@ -1,6 +1,13 @@
|
||||||
require 'yaml'
|
require 'yaml'
|
||||||
include FileUtils
|
include FileUtils
|
||||||
|
|
||||||
|
|
||||||
|
## High level flow of the build:
|
||||||
|
##
|
||||||
|
## clean -> init -> concat -> minify -> package
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
content = File.open('angularFiles.js', 'r') {|f| f.read }
|
content = File.open('angularFiles.js', 'r') {|f| f.read }
|
||||||
files = eval(content.gsub(/\};(\s|\S)*/, '}').
|
files = eval(content.gsub(/\};(\s|\S)*/, '}').
|
||||||
gsub(/angularFiles = /, '').
|
gsub(/angularFiles = /, '').
|
||||||
|
|
@ -9,7 +16,7 @@ files = eval(content.gsub(/\};(\s|\S)*/, '}').
|
||||||
|
|
||||||
BUILD_DIR = 'build'
|
BUILD_DIR = 'build'
|
||||||
|
|
||||||
task :default => [:compile, :test]
|
task :default => [:package]
|
||||||
|
|
||||||
|
|
||||||
desc 'Init the build workspace'
|
desc 'Init the build workspace'
|
||||||
|
|
@ -19,12 +26,13 @@ task :init do
|
||||||
v = YAML::load( File.open( 'version.yaml' ) )
|
v = YAML::load( File.open( 'version.yaml' ) )
|
||||||
match = v['version'].match(/^([^-]*)(-snapshot)?$/)
|
match = v['version'].match(/^([^-]*)(-snapshot)?$/)
|
||||||
|
|
||||||
NG_VERSION = Struct.new(:full, :major, :minor, :dot, :codename).
|
NG_VERSION = Struct.new(:full, :major, :minor, :dot, :codename, :stable).
|
||||||
new(match[1] + (match[2] ? ('-' + %x(git rev-parse HEAD)[0..7]) : ''),
|
new(match[1] + (match[2] ? ('-' + %x(git rev-parse HEAD)[0..7]) : ''),
|
||||||
match[1].split('.')[0],
|
match[1].split('.')[0],
|
||||||
match[1].split('.')[1],
|
match[1].split('.')[1],
|
||||||
match[1].split('.')[2].sub(/\D+.*$/, ''),
|
match[1].split('.')[2].sub(/\D+.*$/, ''),
|
||||||
v['codename'])
|
v['codename'],
|
||||||
|
v['stable'])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -35,8 +43,8 @@ task :clean do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
desc 'Compile Scenario'
|
desc 'Concat Scenario'
|
||||||
task :compile_scenario => :init do
|
task :concat_scenario => :init do
|
||||||
|
|
||||||
concat_file('angular-scenario.js', [
|
concat_file('angular-scenario.js', [
|
||||||
'lib/jquery/jquery.js',
|
'lib/jquery/jquery.js',
|
||||||
|
|
@ -47,8 +55,9 @@ task :compile_scenario => :init do
|
||||||
], gen_css('css/angular.css') + "\n" + gen_css('css/angular-scenario.css'))
|
], gen_css('css/angular.css') + "\n" + gen_css('css/angular-scenario.css'))
|
||||||
end
|
end
|
||||||
|
|
||||||
desc 'Compile JSTD Scenario Adapter'
|
|
||||||
task :compile_jstd_scenario_adapter => :init do
|
desc 'Concat JSTD Scenario Adapter'
|
||||||
|
task :concat_jstd_scenario_adapter => :init do
|
||||||
|
|
||||||
concat_file('jstd-scenario-adapter.js', [
|
concat_file('jstd-scenario-adapter.js', [
|
||||||
'src/ngScenario/jstd-scenario-adapter/angular.prefix',
|
'src/ngScenario/jstd-scenario-adapter/angular.prefix',
|
||||||
|
|
@ -66,9 +75,9 @@ task :compile_jstd_scenario_adapter => :init do
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
desc 'Compile JavaScript'
|
|
||||||
task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
|
|
||||||
|
|
||||||
|
desc 'Concat AngularJS files'
|
||||||
|
task :concat => :init do
|
||||||
concat_file('angular.js', [
|
concat_file('angular.js', [
|
||||||
'src/angular.prefix',
|
'src/angular.prefix',
|
||||||
files['angularSrc'],
|
files['angularSrc'],
|
||||||
|
|
@ -98,99 +107,60 @@ task :compile => [:init, :compile_scenario, :compile_jstd_scenario_adapter] do
|
||||||
|
|
||||||
FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js')
|
FileUtils.cp 'src/ngMock/angular-mocks.js', path_to('angular-mocks.js')
|
||||||
|
|
||||||
closure_compile('angular.js')
|
rewrite_file(path_to('angular-mocks.js')) do |content|
|
||||||
closure_compile('angular-cookies.js')
|
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
|
||||||
closure_compile('angular-loader.js')
|
end
|
||||||
closure_compile('angular-resource.js')
|
end
|
||||||
closure_compile('angular-sanitize.js')
|
|
||||||
closure_compile('angular-bootstrap.js')
|
|
||||||
closure_compile('angular-bootstrap-prettify.js')
|
|
||||||
|
|
||||||
|
|
||||||
|
desc 'Minify JavaScript'
|
||||||
|
task :minify => [:init, :concat, :concat_scenario, :concat_jstd_scenario_adapter] do
|
||||||
|
[ 'angular.js',
|
||||||
|
'angular-cookies.js',
|
||||||
|
'angular-loader.js',
|
||||||
|
'angular-resource.js',
|
||||||
|
'angular-sanitize.js',
|
||||||
|
'angular-bootstrap.js',
|
||||||
|
'angular-bootstrap-prettify.js'
|
||||||
|
].each do |file|
|
||||||
|
closure_compile(file)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
desc 'Generate docs'
|
desc 'Generate docs'
|
||||||
task :docs => [:init] do
|
task :docs => [:init] do
|
||||||
`node docs/src/gen-docs.js`
|
`node docs/src/gen-docs.js`
|
||||||
rewrite_file(path_to('docs/.htaccess')) do |content|
|
|
||||||
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
|
[ path_to('docs/.htaccess'),
|
||||||
|
path_to('docs/index.html'),
|
||||||
|
path_to('docs/index-debug.html'),
|
||||||
|
path_to('docs/index-nocache.html'),
|
||||||
|
path_to('docs/index-jq.html'),
|
||||||
|
path_to('docs/index-jq-debug.html'),
|
||||||
|
path_to('docs/index-jq-nocache.html'),
|
||||||
|
path_to('docs/docs-scenario.html')
|
||||||
|
].each do |src|
|
||||||
|
rewrite_file(src) do |content|
|
||||||
|
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full).
|
||||||
|
sub('"NG_VERSION_STABLE"', NG_VERSION.stable)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
desc 'Create angular distribution'
|
desc 'Create angular distribution'
|
||||||
task :package => [:clean, :compile, :docs] do
|
task :package => [:clean, :minify, :docs] do
|
||||||
tarball = "angular-#{NG_VERSION.full}.tgz"
|
zip_dir = "angular-#{NG_VERSION.full}"
|
||||||
|
zip_file = "#{zip_dir}.zip"
|
||||||
|
|
||||||
pkg_dir = path_to("pkg/angular-#{NG_VERSION.full}")
|
FileUtils.ln_s BUILD_DIR, zip_dir
|
||||||
FileUtils.rm_r(path_to('pkg'), :force => true)
|
%x(zip -r #{zip_file} #{zip_dir})
|
||||||
FileUtils.mkdir_p(pkg_dir)
|
FileUtils.rm zip_dir
|
||||||
|
|
||||||
[ path_to('angular.js'),
|
FileUtils.mv zip_file, path_to(zip_file)
|
||||||
path_to('angular.min.js'),
|
|
||||||
path_to('angular-loader.js'),
|
|
||||||
path_to('angular-loader.min.js'),
|
|
||||||
path_to('angular-bootstrap.js'),
|
|
||||||
path_to('angular-bootstrap.min.js'),
|
|
||||||
path_to('angular-bootstrap-prettify.js'),
|
|
||||||
path_to('angular-bootstrap-prettify.min.js'),
|
|
||||||
path_to('angular-mocks.js'),
|
|
||||||
path_to('angular-cookies.js'),
|
|
||||||
path_to('angular-cookies.min.js'),
|
|
||||||
path_to('angular-resource.js'),
|
|
||||||
path_to('angular-resource.min.js'),
|
|
||||||
path_to('angular-sanitize.js'),
|
|
||||||
path_to('angular-sanitize.min.js'),
|
|
||||||
path_to('angular-scenario.js'),
|
|
||||||
path_to('jstd-scenario-adapter.js'),
|
|
||||||
path_to('jstd-scenario-adapter-config.js'),
|
|
||||||
].each do |src|
|
|
||||||
dest = src.gsub(/^.*\//, '').gsub(/((\.min)?\.js)$/, "-#{NG_VERSION.full}\\1")
|
|
||||||
FileUtils.cp(src, pkg_dir + '/' + dest)
|
|
||||||
end
|
|
||||||
|
|
||||||
FileUtils.cp_r path_to('i18n'), "#{pkg_dir}/i18n-#{NG_VERSION.full}"
|
puts "Package created: #{path_to(zip_file)}"
|
||||||
FileUtils.cp_r path_to('docs'), "#{pkg_dir}/docs-#{NG_VERSION.full}"
|
|
||||||
|
|
||||||
rewrite_file("#{pkg_dir}/angular-mocks-#{NG_VERSION.full}.js") do |content|
|
|
||||||
content.sub!('"NG_VERSION_FULL"', NG_VERSION.full)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/index.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-nocache.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-nocache.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-debug.html",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/index-jq-debug.html"
|
|
||||||
].each do |src|
|
|
||||||
rewrite_file(src) do |content|
|
|
||||||
content.gsub!(/'angular(.*)\.js/, '\'angular\1-' + NG_VERSION.full + '.js')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
rewrite_file("#{pkg_dir}/docs-#{NG_VERSION.full}/docs-scenario.html") do |content|
|
|
||||||
content.sub!('angular-scenario.js', "angular-scenario-#{NG_VERSION.full}.js")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
[ "#{pkg_dir}/docs-#{NG_VERSION.full}/appcache.manifest",
|
|
||||||
"#{pkg_dir}/docs-#{NG_VERSION.full}/appcache-offline.manifest"
|
|
||||||
].each do |src|
|
|
||||||
rewrite_file(src) do |content|
|
|
||||||
content.sub!('../angular.min.js', "angular-#{NG_VERSION.full}.min.js").
|
|
||||||
sub!('/build/docs/', "/#{NG_VERSION.full}/docs-#{NG_VERSION.full}/")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
%x(tar -czf #{path_to(tarball)} -C #{path_to('pkg')} .)
|
|
||||||
|
|
||||||
FileUtils.cp path_to(tarball), pkg_dir
|
|
||||||
FileUtils.mv pkg_dir, path_to(['pkg', NG_VERSION.full])
|
|
||||||
|
|
||||||
puts "Package created: #{path_to(tarball)}"
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -271,7 +241,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
def closure_compile(filename)
|
def closure_compile(filename)
|
||||||
puts "Compiling #{filename} ..."
|
puts "Minifying #{filename} ..."
|
||||||
|
|
||||||
min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
|
min_path = path_to(filename.gsub(/\.js$/, '.min.js'))
|
||||||
|
|
||||||
|
|
@ -289,7 +259,7 @@ end
|
||||||
|
|
||||||
|
|
||||||
def concat_file(filename, deps, footer='')
|
def concat_file(filename, deps, footer='')
|
||||||
puts "Building #{filename} ..."
|
puts "Creating #{filename} ..."
|
||||||
File.open(path_to(filename), 'w') do |f|
|
File.open(path_to(filename), 'w') do |f|
|
||||||
concat = 'cat ' + deps.flatten.join(' ')
|
concat = 'cat ' + deps.flatten.join(' ')
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,6 @@
|
||||||
@name API Reference
|
@name API Reference
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Use the API Refference documentation when you need more information about a specific feature. Check out
|
Use the API Reference documentation when you need more information about a specific feature. Check out
|
||||||
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recomend the
|
{@link guide/ Developer Guide} for AngularJS concepts. If you are new to AngularJS we recomend the
|
||||||
{@link tutorial/ Tutorial}.
|
{@link tutorial/ Tutorial}.
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ initialization.
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
* Place the `script` tag at the buttom of the page. Placing script tags at the end of the page
|
* Place the `script` tag at the bottom of the page. Placing script tags at the end of the page
|
||||||
improves app load time becouse the HTML loading is not blocked by loading of the `angular.js`
|
improves app load time because the HTML loading is not blocked by loading of the `angular.js`
|
||||||
script. You can get the latest bits from {@link http://code.angularjs.org}. Please don't link
|
script. You can get the latest bits from {@link http://code.angularjs.org}. Please don't link
|
||||||
your production code to this URL, as it will expose a security hole on your site. For
|
your production code to this URL, as it will expose a security hole on your site. For
|
||||||
experimental development linking to our site is fine.
|
experimental development linking to our site is fine.
|
||||||
|
|
@ -34,12 +34,12 @@ initialization.
|
||||||
* Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in
|
* Choose: `angular-[version].min.js` for a compressed and obfuscated file, suitable for use in
|
||||||
production.
|
production.
|
||||||
* Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
|
* Place `ng-app` to the root of your application, typically on the `<html>` tag if you want
|
||||||
anugular to auto-bootstrap your application.
|
angular to auto-bootstrap your application.
|
||||||
|
|
||||||
<html ng-app>
|
<html ng-app>
|
||||||
|
|
||||||
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
* If you choose to use the old style directive syntax `ng:` then include xml-namespace in `html`
|
||||||
to make IE happy. (This is here for historical resons, and we no longer recomend use of
|
to make IE happy. (This is here for historical reasons, and we no longer recommend use of
|
||||||
`ng:`.)
|
`ng:`.)
|
||||||
|
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
|
Angular's {@link api/ng.$compile HTML compiler} allows the developer to teach the
|
||||||
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
|
browser new HTML syntax. The compiler allows you to attach behavior to any HTML element or attribute
|
||||||
and even create new HTML element or attributes with custom behavior. Angular calls these behavior
|
and even create new HTML element or attributes with custom behavior. Angular calls these behavior
|
||||||
extensions {@link api/ng.$compileProvider.directive directives}.
|
extensions {@link api/ng.$compileProvider#directive directives}.
|
||||||
|
|
||||||
HTML has a lot of constructs for formatting the HTML for static documents in declarative fashion.
|
HTML has a lot of constructs for formatting the HTML for static documents in declarative fashion.
|
||||||
For example if something needs to be centered, there is no need to provide instructions to the
|
For example if something needs to be centered, there is no need to provide instructions to the
|
||||||
|
|
@ -60,7 +60,7 @@ api/ng.directive:ngBind `ng-bind`} directive.
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Directive is just a function which executes when the compiler encounters it in the DOM. See {@link
|
Directive is just a function which executes when the compiler encounters it in the DOM. See {@link
|
||||||
api/ng.$compileProvider.directive directive API} for in depth documentation on how
|
api/ng.$compileProvider#directive directive API} for in-depth documentation on how
|
||||||
to write directives.
|
to write directives.
|
||||||
|
|
||||||
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the
|
Here is a directive which makes any element draggable. Notice the `draggable` attribute on the
|
||||||
|
|
|
||||||
467
docs/content/guide/concepts.ngdoc
Normal file
|
|
@ -0,0 +1,467 @@
|
||||||
|
@ngdoc overview
|
||||||
|
@name Conceptual Overview
|
||||||
|
@description
|
||||||
|
|
||||||
|
# Overview
|
||||||
|
|
||||||
|
This document gives a quick overview of the main angular components and how they work together.
|
||||||
|
These are:
|
||||||
|
|
||||||
|
* {@link concepts#startup startup} - bring up hello world
|
||||||
|
* {@link concepts#runtime runtime} - overview of angular runtime
|
||||||
|
* {@link concepts#scope scope} - the glue between the view and the controller
|
||||||
|
* {@link concepts#controller controller} - application behavior
|
||||||
|
* {@link concepts#model model} - your application data
|
||||||
|
* {@link concepts#view view} - what the user sees
|
||||||
|
* {@link concepts#directives directives} - extend HTML vocabulary
|
||||||
|
* {@link concepts#filters filters} - format the data in user locale
|
||||||
|
* {@link concepts#injector injector} - assembles your application
|
||||||
|
* {@link concepts#module module} - configures the injector
|
||||||
|
* {@link concepts#angular_namespace `$`} - angular namespace
|
||||||
|
|
||||||
|
<a name="startup"></a>
|
||||||
|
# Startup
|
||||||
|
|
||||||
|
This is how we get the ball rolling (refer to the diagram and example below):
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em;" src="img/guide/concepts-startup.png">
|
||||||
|
|
||||||
|
1. Browser loads the HTML and parses it into a DOM
|
||||||
|
2. Browser loads `angular.js` script
|
||||||
|
3. Angular waits for `DOMContentLoaded` event
|
||||||
|
4. Angular looks for {@link api/ng.directive:ngApp ng-app}
|
||||||
|
{@link guide/directive directive}, which designates application boundary
|
||||||
|
5. {@link guide/module Module} specified in {@link
|
||||||
|
api/ng.directive:ngApp ng-app} (if any) is used to configure
|
||||||
|
the {@link api/AUTO.$injector $injector}
|
||||||
|
6. {@link api/AUTO.$injector $injector} is used to create the {@link
|
||||||
|
api/ng.$compile $compile} service as well as {@link
|
||||||
|
api/ng.$rootScope $rootScope}
|
||||||
|
7. {@link api/ng.$compile $compile} service is used to compile the DOM and link
|
||||||
|
it with {@link api/ng.$rootScope $rootScope}
|
||||||
|
8. {@link api/ng.directive:ngInit ng-init} {@link
|
||||||
|
guide/directive directive} assigns `World` to the `name` property on the {@link guide/scope
|
||||||
|
scope}
|
||||||
|
9. The `{{name}}` {@link api/ng.$interpolate interpolates} the expression to
|
||||||
|
`Hello World!`
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<p ng-init=" name='World' ">Hello {{name}}!</p>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="runtime"></a>
|
||||||
|
# Runtime
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-runtime.png">
|
||||||
|
|
||||||
|
The diagram and the example below describe how Angular interacts with browser's event loop.
|
||||||
|
|
||||||
|
1. Browsers event-loop waits for an event to arrive. Event is a user interactions, timer event,
|
||||||
|
or network event (response from a server).
|
||||||
|
2. The events callback gets executed. This enters the JavaScript context. The callback can
|
||||||
|
modify the DOM structure.
|
||||||
|
3. Once the callback finishes execution, the browser leaves the JavaScript context and
|
||||||
|
re-renders the view based on DOM changes.
|
||||||
|
|
||||||
|
Angular modifies the normal JavaScript flow by providing it's own event processing loop. This
|
||||||
|
splits the JavaScript into classical and Angular execution context. Only operations which are
|
||||||
|
applied in Angular execution context will benefit from angular data-binding, exception handling,
|
||||||
|
property watching, etc... Use $apply() to enter Angular execution context from JavaScript. Keep in
|
||||||
|
mind that in most places (controllers, services) the $apply has already been called for you by the
|
||||||
|
directive which is handling the event. The need to call $apply is reserved only when
|
||||||
|
implementing custom event callbacks, or when working with a third-party library callbacks.
|
||||||
|
|
||||||
|
1. Enter Angular execution context by calling {@link guide/scope scope}`.`{@link
|
||||||
|
api/ng.$rootScope.Scope#$apply $apply}`(stimulusFn)`. Where `stimulusFn` is
|
||||||
|
the work you wish to do in Angular execution context.
|
||||||
|
2. Angular executes the `stimulusFn()`, which typically modifies application state.
|
||||||
|
3. Angular enters the {@link api/ng.$rootScope.Scope#$digest $digest} loop. The
|
||||||
|
loop is made up of two smaller loops which process {@link
|
||||||
|
api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue and the {@link
|
||||||
|
api/ng.$rootScope.Scope#$watch $watch} list. The {@link
|
||||||
|
api/ng.$rootScope.Scope#$digest $digest} loop keeps iterating until the model
|
||||||
|
stabilizes, which means that the {@link api/ng.$rootScope.Scope#$evalAsync
|
||||||
|
$evalAsync} queue is empty and the {@link api/ng.$rootScope.Scope#$watch
|
||||||
|
$watch} list does not detect any changes.
|
||||||
|
4. The {@link api/ng.$rootScope.Scope#$evalAsync $evalAsync} queue is used to
|
||||||
|
schedule work which needs to occur outside of current stack frame, but before the browser
|
||||||
|
view render. This is usually done with `setTimeout(0)`, but the `setTimeout(0)` approach
|
||||||
|
suffers from slowness and may cause view flickering since the browser renders the view after
|
||||||
|
each event.
|
||||||
|
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list is a set of expressions
|
||||||
|
which may have changed since last iteration. If a change is detected then the `$watch`
|
||||||
|
function is called which typically updates the DOM with the new value.
|
||||||
|
6. Once Angular {@link api/ng.$rootScope.Scope#$digest $digest} loop finishes
|
||||||
|
the execution leaves the Angular and JavaScript context. This is followed by the browser
|
||||||
|
re-rendering the DOM to reflect any changes.
|
||||||
|
|
||||||
|
|
||||||
|
Here is the explanation of how the `Hello wold` example achieves the data-binding effect when the
|
||||||
|
user enters text into the text field.
|
||||||
|
|
||||||
|
1. During the compilation phase:
|
||||||
|
1. the {@link api/ng.directive:ngModel ng-model} and {@link
|
||||||
|
api/ng.directive:input input} {@link guide/directive
|
||||||
|
directive} set up a `keydown` listener on the `<input>` control.
|
||||||
|
2. the {@link api/ng.$interpolate {{name}} } interpolation
|
||||||
|
sets up a {@link api/ng.$rootScope.Scope#$watch $watch} to be notified of
|
||||||
|
`name` changes.
|
||||||
|
2. During the runtime phase:
|
||||||
|
1. Pressing an '`X`' key causes the browser to emit a `keydown` event on the input control.
|
||||||
|
2. The {@link api/ng.directive:input input} directive
|
||||||
|
captures the change to the input's value and calls {@link
|
||||||
|
api/ng.$rootScope.Scope#$apply $apply}`("name = 'X';")` to update the
|
||||||
|
application model inside the Angular execution context.
|
||||||
|
3. Angular applies the `name = 'X';` to the model.
|
||||||
|
4. The {@link api/ng.$rootScope.Scope#$digest $digest} loop begins
|
||||||
|
5. The {@link api/ng.$rootScope.Scope#$watch $watch} list detects a change
|
||||||
|
on the `name` property and notifies the {@link api/ng.$interpolate
|
||||||
|
{{name}} } interpolation, which in turn updates the DOM.
|
||||||
|
6. Angular exits the execution context, which in turn exits the `keydown` event and with it
|
||||||
|
the JavaScript execution context.
|
||||||
|
7. The browser re-renders the view with update text.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<input ng-model="name">
|
||||||
|
<p>Hello {{name}}!</p>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<a name="scope"></a>
|
||||||
|
#Scope
|
||||||
|
|
||||||
|
The {@link guide/scope scope} is responsible for detecting changes to the model section and
|
||||||
|
provides the execution context for expressions. The scopes are nested in a hierarchical structure
|
||||||
|
which closely follow the DOM structure. (See individual directive documentation to see which
|
||||||
|
directives cause a creation of new scopes.)
|
||||||
|
|
||||||
|
The following example demonstrates how `name` {@link guide/expression expression} will evaluate
|
||||||
|
into different value depending on which scope it is evaluated in. The example is followed by
|
||||||
|
a diagram depicting the scope boundaries.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<div class="show-scope">
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="GreetCtrl">
|
||||||
|
Hello {{name}}!
|
||||||
|
</div>
|
||||||
|
<div ng-controller="ListCtrl">
|
||||||
|
<ol>
|
||||||
|
<li ng-repeat="name in names">{{name}}</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
<file name="script.js">
|
||||||
|
function GreetCtrl($scope) {
|
||||||
|
$scope.name = 'World';
|
||||||
|
}
|
||||||
|
|
||||||
|
function ListCtrl($scope) {
|
||||||
|
$scope.names = ['Igor', 'Misko', 'Vojta'];
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
<file name="style.css">
|
||||||
|
.show-scope .doc-example-live.ng-scope,
|
||||||
|
.show-scope .doc-example-live .ng-scope {
|
||||||
|
border: 1px solid red;
|
||||||
|
margin: 3px;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<img class="center" src="img/guide/concepts-scope.png">
|
||||||
|
|
||||||
|
|
||||||
|
<a name="controller"></a>
|
||||||
|
# Controller
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-controller.png">
|
||||||
|
|
||||||
|
Controller is the code behind the view. Its job is to construct the model and publish it to the
|
||||||
|
view along with callback methods. The view is a projection of the scope onto the template (the
|
||||||
|
HTML). The scope is the glue which marshals the model to the view and forwards the events to the
|
||||||
|
controller.
|
||||||
|
|
||||||
|
The separation of the controller and the view is important because:
|
||||||
|
|
||||||
|
* The controller is written in JavaScript. JavaScript is imperative. Imperative is a good fit
|
||||||
|
for specifying application behavior. The controller should not contain any rendering
|
||||||
|
information (DOM references or HTML fragments).
|
||||||
|
* The view template is written in HTML. HTML is declarative. Declarative is a good fit for
|
||||||
|
specifying UI. The View should not contain any behavior.
|
||||||
|
* Since the controller is unaware of the view, there could be many views for the same
|
||||||
|
controller. This is important for re-skinning, device specific views (i.e. mobile vs desktop),
|
||||||
|
and testability.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="MyCtrl">
|
||||||
|
Hello {{name}}!
|
||||||
|
<button ng-click="action()">
|
||||||
|
OK
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
<file name="script.js">
|
||||||
|
function MyCtrl($scope) {
|
||||||
|
$scope.action = function() {
|
||||||
|
$scope.name = 'OK';
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.name = 'World';
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="model"></a>
|
||||||
|
# Model
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-model.png">
|
||||||
|
|
||||||
|
The model is the data which is used merged with the template to produce the view. To be able to
|
||||||
|
render the model into the view, the model has to be referenceable from the scope. Unlike many
|
||||||
|
other frameworks Angular makes no restrictions or requirements an the model. There are no classes
|
||||||
|
to inherit from or special accessor methods for accessing or changing the model. The model can be
|
||||||
|
primitive, object hash, or a full object Type. In short the model is a plain JavaScript object.
|
||||||
|
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="view"></a>
|
||||||
|
# View
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-view.png">
|
||||||
|
|
||||||
|
The view is what the users sees. The view begins its life as a template, it is merged with the
|
||||||
|
model and finally rendered into the browser DOM. Angular takes a very different approach to
|
||||||
|
rendering the view, to most other templating systems.
|
||||||
|
|
||||||
|
* **Others** - Most templating systems begin as an HTML string with special templating markup.
|
||||||
|
Often the template markup breaks the HTML syntax which means that the template can not be
|
||||||
|
edited by an HTML editor. The template string is then parsed by the template engine, and
|
||||||
|
merged with the data. The result of the merge is an HTML string. The HTML string is then
|
||||||
|
written to the browser using the `.innerHTML`, which causes the browser to render the HTML.
|
||||||
|
When the model changes the whole process needs to be repeated. The granularity of the template
|
||||||
|
is the granularity of the DOM updates. The key here is that the templating system manipulates
|
||||||
|
strings.
|
||||||
|
* **Angular** - Angular is different, since its templating system works on DOM objects not on
|
||||||
|
strings. The template is still written in HTML string, but it is HTML (not HTML with
|
||||||
|
template sprinkled in.) The browser parses the HTML into DOM, and the DOM becomes the input to
|
||||||
|
the template engine know as the {@link api/ng.$compile compiler}. The compiler
|
||||||
|
looks for {@link guide/directive directives} which in turn set up {@link
|
||||||
|
api/ng.$rootScope.Scope#$watch watches} on the model. The result is a
|
||||||
|
continuously updating view which does not need template model re-merging. Your model becomes
|
||||||
|
the single source-of-truth for your view.
|
||||||
|
|
||||||
|
<div class="clear">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
|
||||||
|
<input ng-model="list" ng-list> <br>
|
||||||
|
<input ng-model="list" ng-list> <br>
|
||||||
|
<pre>list={{list}}</pre> <br>
|
||||||
|
<ol>
|
||||||
|
<li ng-repeat="item in list">
|
||||||
|
{{item}}
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="directives"></a>
|
||||||
|
# Directives
|
||||||
|
|
||||||
|
A directive is a behavior or DOM transformation which is triggered by a presence of an attribute,
|
||||||
|
element name, or a class name. A directive allows you to extend the HTML vocabulary in a
|
||||||
|
declarative fashion. Following is an example which enables data-binding for the `contenteditable`
|
||||||
|
in HTML.
|
||||||
|
|
||||||
|
<example module="directive">
|
||||||
|
<file name="script.js">
|
||||||
|
angular.module('directive', []).directive('contenteditable', function() {
|
||||||
|
return {
|
||||||
|
require: 'ngModel',
|
||||||
|
link: function(scope, elm, attrs, ctrl) {
|
||||||
|
// view -> model
|
||||||
|
elm.bind('blur', function() {
|
||||||
|
scope.$apply(function() {
|
||||||
|
ctrl.$setViewValue(elm.html());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// model -> view
|
||||||
|
ctrl.render = function(value) {
|
||||||
|
elm.html(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
// load init value from DOM
|
||||||
|
ctrl.$setViewValue(elm.html());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});
|
||||||
|
</file>
|
||||||
|
<file name="index.html">
|
||||||
|
<div contentEditable="true" ng-model="content">Edit Me</div>
|
||||||
|
<pre>model = {{content}}</pre>
|
||||||
|
</file>
|
||||||
|
<file name="style.css">
|
||||||
|
div[contentEditable] {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #D0D0D0;
|
||||||
|
margin-bottom: 1em;
|
||||||
|
padding: 1em;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<a name="filters"></a>
|
||||||
|
# Filters
|
||||||
|
|
||||||
|
{@link api/ng.$filter Filters} perform data transformation roles. Typically
|
||||||
|
they are used in conjunction with the locale to format the data in locale specific output.
|
||||||
|
They are follow the spirit of UNIX filters and follow similar syntax `|` (pipe).
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-init="list = ['Chrome', 'Safari', 'Firefox', 'IE'] ">
|
||||||
|
Number formatting: {{ 1234567890 | number }} <br>
|
||||||
|
array filtering <input ng-model="predicate">
|
||||||
|
{{ list | filter:predicate | json }}
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="module"></a>
|
||||||
|
<a name="injector"></a>
|
||||||
|
# Modules and the Injector
|
||||||
|
|
||||||
|
<img class="pull-right" style="padding-left: 3em; padding-bottom: 1em;" src="img/guide/concepts-module-injector.png">
|
||||||
|
|
||||||
|
An {@link api/AUTO.$injector injector} is a service locator. There is a single
|
||||||
|
{@link api/AUTO.$injector injector} per Angular {@link
|
||||||
|
api/ng.directive:ngApp application}. The {@link
|
||||||
|
api/AUTO.$injector injector} provides a way to look up an object instance by its
|
||||||
|
name. The injector keeps on internal cache of all objects so that repeated calls to get the same
|
||||||
|
object name result in the same instance. If the object does not exist, then the {@link
|
||||||
|
api/AUTO.$injector injector} asks the instance factory to create a new instance.
|
||||||
|
|
||||||
|
A {@link api/angular.Module module} is a way to configure the injector's instance factory, known
|
||||||
|
as a {@link api/AUTO.$provide provider}.
|
||||||
|
|
||||||
|
<div class='clear'></div>
|
||||||
|
<pre>
|
||||||
|
// Create a module
|
||||||
|
var myModule = angular.module('myModule', [])
|
||||||
|
|
||||||
|
// Configure the injector
|
||||||
|
myModule.factory('serviceA', function() {
|
||||||
|
return {
|
||||||
|
// instead of {}, put your object creation here
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
// create an injector and configure it from 'myModule'
|
||||||
|
var $injector = angular.injector('myModule');
|
||||||
|
|
||||||
|
// retrieve an object from the injector by name
|
||||||
|
var serviceA = $injector.get('serviceA');
|
||||||
|
|
||||||
|
// always true because of instance cache
|
||||||
|
$injector.get('serviceA') === $injector.get('serviceA');
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
|
But the real magic of the {@link api/AUTO.$injector injector} is that it can be
|
||||||
|
used to {@link api/AUTO.$injector#invoke call} methods and {@link
|
||||||
|
api/AUTO.$injector#instantiate instantiate} types. This subtle feature is what
|
||||||
|
allows the methods and types to ask for their dependencies rather then to look for them.
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
// You write functions such as this one.
|
||||||
|
function doSomething(serviceA, serviceB) {
|
||||||
|
// do something here.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Angular provides the injector for your application
|
||||||
|
var $injector = ...;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// the old-school way of getting dependencies.
|
||||||
|
var serviceA = $injector.get('serviceA');
|
||||||
|
var serviceB = $injector.get('serviceB');
|
||||||
|
|
||||||
|
// now call the function
|
||||||
|
doSomething(serviceA, serviceB);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////
|
||||||
|
// the cool way of getting dependencies.
|
||||||
|
// the $injector will supply the arguments to the function automatically
|
||||||
|
$injector.invoke(doSomething); // This is how the framework calls your functions
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
Notice that the only thing you needed to write was the function, and list the dependencies in the
|
||||||
|
function arguments. When angular calls the function, it will use the {@link
|
||||||
|
api/AUTO.$injector#invoke call} which will automatically fill the function
|
||||||
|
arguments.
|
||||||
|
|
||||||
|
Examine the `ClockCtrl` bellow, and notice how it list the dependencies in constructor. When the
|
||||||
|
{@link api/ng.directive:ngController ng-controller} instantiates
|
||||||
|
the controller it automatically provides the dependencies. There is no need to create
|
||||||
|
dependencies, look for dependencies, or even get a reference to the injector.
|
||||||
|
|
||||||
|
<example module="timeExampleModule">
|
||||||
|
<file name="index.html">
|
||||||
|
<div ng-controller="ClockCtrl">
|
||||||
|
Current time is: {{ time.now }}
|
||||||
|
</div>
|
||||||
|
</file>
|
||||||
|
<file name="script.js">
|
||||||
|
angular.module('timeExampleModule', []).
|
||||||
|
// Declare new object call time,
|
||||||
|
// which will be available for injection
|
||||||
|
factory('time', function($timeout) {
|
||||||
|
var time = {};
|
||||||
|
|
||||||
|
(function tick() {
|
||||||
|
time.now = new Date().toString();
|
||||||
|
$timeout(tick, 1000);
|
||||||
|
})();
|
||||||
|
return time;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Notice that you can simply ask for time
|
||||||
|
// and it will be provided. No need to look for it.
|
||||||
|
function ClockCtrl($scope, time) {
|
||||||
|
$scope.time = time;
|
||||||
|
}
|
||||||
|
</file>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="angular_namespace"></a>
|
||||||
|
# Angular Namespace
|
||||||
|
|
||||||
|
To prevent accidental name collision, Angular prefixes names of objects which could potentially
|
||||||
|
collide with `$`. Please do not use the `$` prefix in your code as it may accidentally collide
|
||||||
|
with Angular code.
|
||||||
|
|
@ -253,7 +253,7 @@ describe('state', function() {
|
||||||
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
|
var mainCtrl = $controller(MainCtrl, {$scope: mainScope});
|
||||||
childScope = mainScope.$new();
|
childScope = mainScope.$new();
|
||||||
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
|
var childCtrl = $controller(ChildCtrl, {$scope: childScope});
|
||||||
babyScope = $rootScope.$new();
|
babyScope = childCtrl.$new();
|
||||||
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
|
var babyCtrl = $controller(BabyCtrl, {$scope: babyScope});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -331,11 +331,11 @@ to entry point of your application (e.g. index.html)
|
||||||
|
|
||||||
### Crawling your app
|
### Crawling your app
|
||||||
|
|
||||||
If you want your AJAX application to be indexed by web crawlers, you rill need to add the following
|
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:
|
meta tag to the HEAD section of your document:
|
||||||
<pre><meta name="fragment" content="!" /></pre>
|
<pre><meta name="fragment" content="!" /></pre>
|
||||||
|
|
||||||
This statement causes a crawler to request links with empty `_escaped_fragment_` parameter so that
|
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
|
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
|
technique, see {@link http://code.google.com/web/ajaxcrawling/docs/specification.html Making AJAX
|
||||||
Applications Crawlable}.
|
Applications Crawlable}.
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@
|
||||||
@name Developer Guide: Angular Services: Creating Services
|
@name Developer Guide: Angular Services: Creating Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
While angular offers several useful services, for any nontrivial application you'll find it useful
|
While Angular offers several useful services, for any nontrivial application you'll find it useful
|
||||||
to write your own custom services. To do this you begin by registering a service factory function
|
to write your own custom services. To do this you begin by registering a service factory function
|
||||||
with a module either via the {@link api/angular.module Module#factory api} or directly
|
with a module either via the {@link api/angular.module Module#factory api} or directly
|
||||||
via the {@link api/AUTO.$provide $provide} api inside of module config function.
|
via the {@link api/AUTO.$provide $provide} api inside of module config function.
|
||||||
|
|
||||||
All angular services participate in {@link di dependency injection (DI)} by registering
|
All Angular services participate in {@link di dependency injection (DI)} by registering
|
||||||
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
themselves with Angular's DI system (injector) under a `name` (id) as well as by declaring
|
||||||
dependencies which need to be provided for the factory function of the registered service. The
|
dependencies which need to be provided for the factory function of the registered service. The
|
||||||
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
ability to swap dependencies for mocks/stubs/dummies in tests allows for services to be highly
|
||||||
|
|
@ -76,17 +76,17 @@ angular.module('myModule', [], function($provide) {
|
||||||
|
|
||||||
# Instantiating Angular Services
|
# Instantiating Angular Services
|
||||||
|
|
||||||
All services in Angular are instantiates services lazily, this means that a service will be created
|
All services in Angular are instantiated lazily. This means that a service will be created
|
||||||
only when it is needed for instantiation of a service or an application component that depends on it.
|
only when it is needed for instantiation of a service or an application component that depends on it.
|
||||||
In other words, angular won't instantiate lazy services unless they are requested directly or
|
In other words, Angular won't instantiate lazy services unless they are requested directly or
|
||||||
indirectly by the application.
|
indirectly by the application.
|
||||||
|
|
||||||
|
|
||||||
# Services as singletons
|
# Services as singletons
|
||||||
|
|
||||||
Lastly, it is important to realize that all angular services are application singletons. This means
|
Lastly, it is important to realize that all Angular services are application singletons. This means
|
||||||
that there is only one instance of a given service per injector. Since angular is lethally allergic
|
that there is only one instance of a given service per injector. Since Angular is lethally allergic
|
||||||
to the global state, it is possible to create multiple injectors, each with its own instance of a
|
to global state, it is possible to create multiple injectors, each with its own instance of a
|
||||||
given service, but that is rarely needed, except in tests where this property is crucially
|
given service, but that is rarely needed, except in tests where this property is crucially
|
||||||
important.
|
important.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
@name Developer Guide: Angular Services: Testing Angular Services
|
@name Developer Guide: Angular Services: Testing Angular Services
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Following is a unit test for the service in the example in {@link
|
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
|
dev_guide.services.creating_services Creating Angular Services}. The unit test example uses Jasmine
|
||||||
spy (mock) instead of a real browser alert.
|
spy (mock) instead of a real browser alert.
|
||||||
|
|
||||||
|
|
@ -55,7 +55,7 @@ it('should clear messages after alert', function() {
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
||||||
* {@link dev_guide.services.creating_services Creating Angular Services}
|
* {@link dev_guide.services.creating_services Creating Angular Services}
|
||||||
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
* {@link dev_guide.services.managing_dependencies Managing Service Dependencies}
|
||||||
* {@link dev_guide.services.injecting_controllers Injecting Services Into Conrollers}
|
* {@link dev_guide.services.injecting_controllers Injecting Services Into Controllers}
|
||||||
|
|
||||||
## Related API
|
## Related API
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ Angular sets these CSS classes. It is up to your application to provide useful s
|
||||||
|
|
||||||
* `ng-invalid`, `ng-valid`
|
* `ng-invalid`, `ng-valid`
|
||||||
- **Usage:** angular applies this class to an input widget element if that element's input does
|
- **Usage:** angular applies this class to an input widget element if that element's input does
|
||||||
notpass validation. (see {@link api/ng.directive:input input} directive).
|
not pass validation. (see {@link api/ng.directive:input input} directive).
|
||||||
|
|
||||||
* `ng-pristine`, `ng-dirty`
|
* `ng-pristine`, `ng-dirty`
|
||||||
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class
|
- **Usage:** angular {@link api/ng.directive:input input} directive applies `ng-pristine` class
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ because first the template (which is the uncompiled HTML along with any addition
|
||||||
directives) is compiled on the browser, and second, the compilation step produces a live view. We
|
directives) is compiled on the browser, and second, the compilation step produces a live view. We
|
||||||
say live because any changes to the view are immediately reflected in the model, and any changes in
|
say live because any changes to the view are immediately reflected in the model, and any changes in
|
||||||
the model are propagated to the view. This makes the model always the single-source-of-truth for
|
the model are propagated to the view. This makes the model always the single-source-of-truth for
|
||||||
the application state, greatly simplifying the programing model for the developer. You can think of
|
the application state, greatly simplifying the programming model for the developer. You can think of
|
||||||
the view as simply an instant projection of your model.
|
the view as simply an instant projection of your model.
|
||||||
|
|
||||||
Because the view is just a projection of the model, the controller is completely separated from the
|
Because the view is just a projection of the model, the controller is completely separated from the
|
||||||
|
|
|
||||||
|
|
@ -14,9 +14,6 @@ displaying it to the user. You can pass expressions through a chain of filters l
|
||||||
The expression evaluator simply passes the value of name to
|
The expression evaluator simply passes the value of name to
|
||||||
{@link api/ng.filter:uppercase uppercase filter}.
|
{@link api/ng.filter:uppercase uppercase filter}.
|
||||||
|
|
||||||
In addition to formatting data, filters can also modify the DOM. This allows filters to handle
|
|
||||||
tasks such as conditionally applying CSS styles to filtered output.
|
|
||||||
|
|
||||||
|
|
||||||
## Related Topics
|
## Related Topics
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ this may seem obvious it usually is very difficult to be able to call an individ
|
||||||
typical project. The reason is that the developers often time mix concerns, and they end up with a
|
typical project. The reason is that the developers often time mix concerns, and they end up with a
|
||||||
piece of code which does everything. It reads the data from XHR, it sorts it and then it
|
piece of code which does everything. It reads the data from XHR, it sorts it and then it
|
||||||
manipulates the DOM. With angular we try to make it easy for you to do the right thing, and so we
|
manipulates the DOM. With angular we try to make it easy for you to do the right thing, and so we
|
||||||
provide dependency injection for your XHR (which you can mock out) and we crated abstraction which
|
provide dependency injection for your XHR (which you can mock out) and we created abstraction which
|
||||||
allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
|
allow you to sort your model without having to resort to manipulating the DOM. So that in the end,
|
||||||
it is easy to write a sort function which sorts some data, so that your test can create a data set,
|
it is easy to write a sort function which sorts some data, so that your test can create a data set,
|
||||||
apply the function, and assert that the resulting model is in the correct order. The test does not
|
apply the function, and assert that the resulting model is in the correct order. The test does not
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ For example:
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Results in code bloat do to the need of temporary variable:
|
Results in code bloat due to the need of temporary variable:
|
||||||
<pre>
|
<pre>
|
||||||
var greeterFactory = function(renamed$window) {
|
var greeterFactory = function(renamed$window) {
|
||||||
...;
|
...;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ can be extended such that HTML can be turned into a declarative domain specific
|
||||||
|
|
||||||
# Invoking directives from HTML
|
# Invoking directives from HTML
|
||||||
|
|
||||||
Directives have camel cased names such as 'ngBind'. The directive can be invoked by translating
|
Directives have camel cased names such as `ngBind`. The directive can be invoked by translating
|
||||||
the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the
|
the camel case name into snake case with these special characters `:`, `-`, or `_`. Optionally the
|
||||||
directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a
|
directive can be prefixed with `x-`, or `data-` to make it HTML validator compliant. Here is a
|
||||||
list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and
|
list of some of the possible directive names: `ng:bind`, `ng-bind`, `ng_bind`, `x-ng-bind` and
|
||||||
|
|
@ -74,7 +74,7 @@ Compilation of HTML happens in three phases:
|
||||||
realize because the templates must be parsable HTML. This is in contrast to most templating
|
realize because the templates must be parsable HTML. This is in contrast to most templating
|
||||||
systems that operate on strings, rather than on DOM elements.
|
systems that operate on strings, rather than on DOM elements.
|
||||||
|
|
||||||
2. The compilation of the DOM is performed by the call to {@link api/ng.$compile
|
2. The compilation of the DOM is performed by the call to the {@link api/ng.$compile
|
||||||
$compile()} method. The method traverses the DOM and matches the directives. If a match is found
|
$compile()} method. The method traverses the DOM and matches the directives. If a match is found
|
||||||
it is added to the list of directives associated with the given DOM element. Once all directives
|
it is added to the list of directives associated with the given DOM element. Once all directives
|
||||||
for a given DOM element have been identified they are sorted by priority and their `compile()`
|
for a given DOM element have been identified they are sorted by priority and their `compile()`
|
||||||
|
|
@ -109,8 +109,8 @@ Compilation of HTML happens in three phases:
|
||||||
|
|
||||||
## Reasons behind the compile/link separation
|
## Reasons behind the compile/link separation
|
||||||
|
|
||||||
At this point you may wonder why is the compile process broken down to a compile and link phase.
|
At this point you may wonder why the compile process is broken down to a compile and link phase.
|
||||||
To understand this, lets look at a real world example with repeater:
|
To understand this, let's look at a real world example with repeater:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
Hello {{user}}, you have these actions:
|
Hello {{user}}, you have these actions:
|
||||||
|
|
@ -125,7 +125,7 @@ The short answer is that compile and link separation is needed any time a change
|
||||||
a change in DOM structure such as in repeaters.
|
a change in DOM structure such as in repeaters.
|
||||||
|
|
||||||
When the above example is compiled, the compiler visits every node and looks for directives. The
|
When the above example is compiled, the compiler visits every node and looks for directives. The
|
||||||
`{{user}}` is an example of {@link api/ng.$interpolate interpolation} directive. {@link
|
`{{user}}` is an example of an {@link api/ng.$interpolate interpolation} directive. {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} is another directive. But {@link
|
api/ng.directive:ngRepeat ngRepeat} is another directive. But {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} has a dilemma. It needs to be
|
api/ng.directive:ngRepeat ngRepeat} has a dilemma. It needs to be
|
||||||
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
|
able to quickly stamp out new `li`s for every `action` in `user.actions`. This means that it needs
|
||||||
|
|
@ -138,16 +138,16 @@ But compiling on every `li` element clone would be slow, since the compilation r
|
||||||
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
|
traverse the DOM tree and look for directives and execute them. If we put the compilation inside a
|
||||||
repeater which needs to unroll 100 items we would quickly run into performance problems.
|
repeater which needs to unroll 100 items we would quickly run into performance problems.
|
||||||
|
|
||||||
The solution is to break the compilation process into two phases the compile phase where all of
|
The solution is to break the compilation process into two phases; the compile phase where all of
|
||||||
the directives are identified and sorted by priority, and a linking phase where any work which
|
the directives are identified and sorted by priority, and a linking phase where any work which
|
||||||
links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the specific
|
links a specific instance of the {@link api/ng.$rootScope.Scope scope} and the specific
|
||||||
instance of an `li` is performed.
|
instance of an `li` is performed.
|
||||||
|
|
||||||
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
|
{@link api/ng.directive:ngRepeat ngRepeat} works by preventing the
|
||||||
compilation process form descending into `li` element. Instead the {@link
|
compilation process form descending into the `li` element. Instead the {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} directive compiles `li`
|
api/ng.directive:ngRepeat ngRepeat} directive compiles `li`
|
||||||
separately. The result of of the `li` element compilation is a linking function which contains all
|
separately. The result of of the `li` element compilation is a linking function which contains all
|
||||||
of the directives contained in the `li` element ready to be attached to a specific clone of `li`
|
of the directives contained in the `li` element, ready to be attached to a specific clone of the `li`
|
||||||
element. At runtime the {@link api/ng.directive:ngRepeat ngRepeat}
|
element. At runtime the {@link api/ng.directive:ngRepeat ngRepeat}
|
||||||
watches the expression and as items are added to the array it clones the `li` element, creates a
|
watches the expression and as items are added to the array it clones the `li` element, creates a
|
||||||
new {@link api/ng.$rootScope.Scope scope} for the cloned `li` element and calls the
|
new {@link api/ng.$rootScope.Scope scope} for the cloned `li` element and calls the
|
||||||
|
|
@ -156,18 +156,18 @@ link function on the cloned `li`.
|
||||||
Summary:
|
Summary:
|
||||||
|
|
||||||
* *compile function* - The compile function is relatively rare in directives, since most
|
* *compile function* - The compile function is relatively rare in directives, since most
|
||||||
directives are concerned with working with a specific DOM element instance rather then
|
directives are concerned with working with a specific DOM element instance rather than
|
||||||
transforming the template DOM element. Any operation which can be shared among the instance of
|
transforming the template DOM element. Any operation which can be shared among the instance of
|
||||||
directives should be moved to the compile function for performance reasons.
|
directives should be moved to the compile function for performance reasons.
|
||||||
|
|
||||||
* *link function* - It is rare for the directive not to have a link function. Link function
|
* *link function* - It is rare for the directive not to have a link function. A link function
|
||||||
allows the directive to register listeners to the specific cloned DOM element instance as well
|
allows the directive to register listeners to the specific cloned DOM element instance as well
|
||||||
as to copy content into the DOM from the scope.
|
as to copy content into the DOM from the scope.
|
||||||
|
|
||||||
|
|
||||||
# Writing directives (short version)
|
# Writing directives (short version)
|
||||||
|
|
||||||
In this example we will build a directive which displays the current time.
|
In this example we will build a directive that displays the current time.
|
||||||
|
|
||||||
<doc:example module="time">
|
<doc:example module="time">
|
||||||
<doc:source>
|
<doc:source>
|
||||||
|
|
@ -211,17 +211,15 @@ In this example we will build a directive which displays the current time.
|
||||||
$timeout.cancel(timeoutId);
|
$timeout.cancel(timeoutId);
|
||||||
});
|
});
|
||||||
|
|
||||||
updateLater(); // kick of the UI update process.
|
updateLater(); // kick off the UI update process.
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
<div ng-controller="Ctrl2">
|
<div ng-controller="Ctrl2">
|
||||||
Date format: <input ng-model='format'> <hr/>
|
Date format: <input ng-model="format"> <hr/>
|
||||||
Current time is: <span my-current-time="format"></span>
|
Current time is: <span my-current-time="format"></span>
|
||||||
</div>
|
</div>
|
||||||
</doc:source>
|
</doc:source>
|
||||||
<doc:scenario>
|
|
||||||
</doc:scenario>
|
|
||||||
</doc:example>
|
</doc:example>
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -257,7 +255,7 @@ In most cases you will not need such fine control and so the above can be simpli
|
||||||
different parts of this skeleton are explained in following sections. In this section we are
|
different parts of this skeleton are explained in following sections. In this section we are
|
||||||
interested only isomers of this skeleton.
|
interested only isomers of this skeleton.
|
||||||
|
|
||||||
The first step in simplyfing the code is to rely on the deafult values. Therefore the above can be
|
The first step in simplyfing the code is to rely on the default values. Therefore the above can be
|
||||||
simplified as:
|
simplified as:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -273,7 +271,7 @@ simplified as:
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Most directives concern themselves only with instances not with template transformations allowing
|
Most directives concern themselves only with instances, not with template transformations, allowing
|
||||||
further simplification:
|
further simplification:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -290,7 +288,7 @@ further simplification:
|
||||||
The factory method is responsible for creating the directive. It is invoked only once, when the
|
The factory method is responsible for creating the directive. It is invoked only once, when the
|
||||||
{@link api/ng.$compile compiler} matches the directive for the first time. You can
|
{@link api/ng.$compile compiler} matches the directive for the first time. You can
|
||||||
perform any initialization work here. The method is invoked using the {@link
|
perform any initialization work here. The method is invoked using the {@link
|
||||||
http://localhost:8000/build/docs/api/AUTO.$injector#invoke $injector.invoke} which
|
api/AUTO.$injector#invoke $injector.invoke} which
|
||||||
makes it injectable following all of the rules of injection annotation.
|
makes it injectable following all of the rules of injection annotation.
|
||||||
|
|
||||||
## Directive Definition Object
|
## Directive Definition Object
|
||||||
|
|
@ -316,8 +314,8 @@ compiler}. The attributes are:
|
||||||
apply for the root of the template since the root of the template always gets a new scope.
|
apply for the root of the template since the root of the template always gets a new scope.
|
||||||
|
|
||||||
* `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from
|
* `{}` (object hash) - then a new 'isolate' scope is created. The 'isolate' scope differs from
|
||||||
normal scope that it does not prototypically inherit from the parent scope. This is useful
|
normal scope in that it does not prototypically inherit from the parent scope. This is useful
|
||||||
when creating reusable components, which should not accidentally read or modify data in
|
when creating reusable components, which should not accidentally read or modify data in the
|
||||||
parent scope. <br/>
|
parent scope. <br/>
|
||||||
The 'isolate' scope takes an object hash which defines a set of local scope properties
|
The 'isolate' scope takes an object hash which defines a set of local scope properties
|
||||||
derived from the parent scope. These local properties are useful for aliasing values for
|
derived from the parent scope. These local properties are useful for aliasing values for
|
||||||
|
|
@ -344,7 +342,7 @@ compiler}. The attributes are:
|
||||||
`scope: { localFn:'increment()' }`, then isolate scope property `localFn` will point to
|
`scope: { localFn:'increment()' }`, then isolate scope property `localFn` will point to
|
||||||
a function wrapper for the `increment()` expression. Often it's desirable to pass data from
|
a function wrapper for the `increment()` expression. Often it's desirable to pass data from
|
||||||
the isolate scope via an expression and to the parent scope, this can be done by passing a
|
the isolate scope via an expression and to the parent scope, this can be done by passing a
|
||||||
map of local variable names and values into the expression wrapper fn. For example if the
|
map of local variable names and values into the expression wrapper fn. For example, if the
|
||||||
expression is `increment(amount)` then we can specify the amount value by calling the
|
expression is `increment(amount)` then we can specify the amount value by calling the
|
||||||
`localFn` as `localFn({amount: 22})`.
|
`localFn` as `localFn({amount: 22})`.
|
||||||
|
|
||||||
|
|
@ -383,7 +381,7 @@ compiler}. The attributes are:
|
||||||
the template loading is asynchronous the compilation/linking is suspended until the template
|
the template loading is asynchronous the compilation/linking is suspended until the template
|
||||||
is loaded.
|
is loaded.
|
||||||
|
|
||||||
* `replace` - if set to `true` then the template will replace the current element, rather then
|
* `replace` - if set to `true` then the template will replace the current element, rather than
|
||||||
append the template to the element.
|
append the template to the element.
|
||||||
|
|
||||||
* `transclude` - compile the content of the element and make it available to the directive.
|
* `transclude` - compile the content of the element and make it available to the directive.
|
||||||
|
|
@ -409,24 +407,24 @@ compiler}. The attributes are:
|
||||||
function compile(tElement, tAttrs, transclude) { ... }
|
function compile(tElement, tAttrs, transclude) { ... }
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Compile function deals with transforming the template DOM. Since most directives do not do
|
The compile function deals with transforming the template DOM. Since most directives do not do
|
||||||
template transformation, it is not used often. Examples which require compile functions are
|
template transformation, it is not used often. Examples that require compile functions are
|
||||||
directives which transform template DOM such as {@link
|
directives that transform template DOM, such as {@link
|
||||||
api/ng.directive:ngRepeat ngRepeat} or load the contents
|
api/ng.directive:ngRepeat ngRepeat}, or load the contents
|
||||||
asynchronously such as {@link api/ng.directive:ngView ngView}. The
|
asynchronously, such as {@link api/ng.directive:ngView ngView}. The
|
||||||
compile functions takes the following arguments.
|
compile function takes the following arguments.
|
||||||
|
|
||||||
* `tElement` - template element - The element where the directive has been declared. It is
|
* `tElement` - template element - The element where the directive has been declared. It is
|
||||||
safe to do template transformation on the element and child elements only.
|
safe to do template transformation on the element and child elements only.
|
||||||
|
|
||||||
* `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
|
* `tAttrs` - template attributes - Normalized list of attributes declared on this element shared
|
||||||
between all directive compile functions. See {@link
|
between all directive compile functions. See {@link
|
||||||
#Attributes Attributes}
|
guide/directive#Attributes Attributes}.
|
||||||
|
|
||||||
* `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
|
* `transclude` - A transclude linking function: `function(scope, cloneLinkingFn)`.
|
||||||
|
|
||||||
NOTE: The template instance and the link instance may not be the same objects if the template has
|
NOTE: The template instance and the link instance may not be the same objects if the template has
|
||||||
been cloned. For this reason it is not safe in the compile function to do anything other the DOM
|
been cloned. For this reason it is not safe in the compile function to do anything other than DOM
|
||||||
transformation that applies to all DOM clones. Specifically, DOM listener registration should be
|
transformation that applies to all DOM clones. Specifically, DOM listener registration should be
|
||||||
done in a linking function rather than in a compile function.
|
done in a linking function rather than in a compile function.
|
||||||
|
|
||||||
|
|
@ -446,7 +444,7 @@ A compile function can have a return value which can be either a function or an
|
||||||
function link(scope, iElement, iAttrs, controller) { ... }
|
function link(scope, iElement, iAttrs, controller) { ... }
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
Link function is responsible for registering DOM listeners as well as updating the DOM. It is
|
The link function is responsible for registering DOM listeners as well as updating the DOM. It is
|
||||||
executed after the template has been cloned. This is where most of the directive logic will be
|
executed after the template has been cloned. This is where most of the directive logic will be
|
||||||
put.
|
put.
|
||||||
|
|
||||||
|
|
@ -458,7 +456,8 @@ put.
|
||||||
already been linked.
|
already been linked.
|
||||||
|
|
||||||
* `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
|
* `iAttrs` - instance attributes - Normalized list of attributes declared on this element shared
|
||||||
between all directive linking functions. See {@link #Attributes Attributes}
|
between all directive linking functions. See {@link
|
||||||
|
guide/directive#Attributes Attributes}.
|
||||||
|
|
||||||
* `controller` - a controller instance - A controller instance if at least one directive on the
|
* `controller` - a controller instance - A controller instance if at least one directive on the
|
||||||
element defines a controller. The controller is shared among all the directives, which allows
|
element defines a controller. The controller is shared among all the directives, which allows
|
||||||
|
|
@ -478,11 +477,11 @@ Executed after the child elements are linked. Safe to do DOM transformation in h
|
||||||
<a name="Attributes"></a>
|
<a name="Attributes"></a>
|
||||||
## Attributes
|
## Attributes
|
||||||
|
|
||||||
The attributes object - passed as a parameter in the link() or compile() functions - is a way of
|
The {@link api/ng.$compile.directive.Attributes Attributes} object - passed as a parameter in the
|
||||||
accessing:
|
link() or compile() functions - is a way of accessing:
|
||||||
|
|
||||||
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
|
* *normalized attribute names:* Since a directive such as 'ngBind' can be expressed in many ways
|
||||||
sucha s as 'ng:bind', or 'x-ng-bind', the attributes object allows for a normalize accessed to
|
such as 'ng:bind', or 'x-ng-bind', the attributes object allows for normalized accessed to
|
||||||
the attributes.
|
the attributes.
|
||||||
|
|
||||||
* *directive inter-communication:* All directives share the same instance of the attributes
|
* *directive inter-communication:* All directives share the same instance of the attributes
|
||||||
|
|
@ -577,7 +576,7 @@ To solve the issue of lack of isolation, the directive declares a new `isolated`
|
||||||
isolated scope does not prototypically inherit from the child scope, and therefore we don't have
|
isolated scope does not prototypically inherit from the child scope, and therefore we don't have
|
||||||
to worry about accidentally clobbering any properties.
|
to worry about accidentally clobbering any properties.
|
||||||
|
|
||||||
However 'isolated' scope creates a new problem: if a transcluded DOM is a child of the widget
|
However `isolated` scope creates a new problem: if a transcluded DOM is a child of the widget
|
||||||
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
|
isolated scope then it will not be able to bind to anything. For this reason the transcluded scope
|
||||||
is a child of the original scope, before the widget created an isolated scope for its local
|
is a child of the original scope, before the widget created an isolated scope for its local
|
||||||
variables. This makes the transcluded and widget isolated scope siblings.
|
variables. This makes the transcluded and widget isolated scope siblings.
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
@description
|
@description
|
||||||
|
|
||||||
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
|
Expressions are JavaScript-like code snippets that are usually placed in bindings such as `{{
|
||||||
expression }}`. Expressions are process by the {@link api/ng.$parse $parse}
|
expression }}`. Expressions are processed by {@link api/ng.$parse $parse}
|
||||||
service.
|
service.
|
||||||
|
|
||||||
For example, these are all valid expressions in angular:
|
For example, these are all valid expressions in angular:
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@ The following example shows how to add two-way data-binding to contentEditable e
|
||||||
});
|
});
|
||||||
|
|
||||||
// model -> view
|
// model -> view
|
||||||
ctrl.render = function(value) {
|
ctrl.$render = function(value) {
|
||||||
elm.html(value);
|
elm.html(value);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,10 +12,14 @@ on IE v8.0 or earlier.
|
||||||
|
|
||||||
To make your angular application work on IE please make sure that:
|
To make your angular application work on IE please make sure that:
|
||||||
|
|
||||||
1. you **do not** use custom element tags such as `<ng:view>` (use the attribute version `<div
|
1. You polyfill JSON.stringify if necessary (IE7 will need this). You can use
|
||||||
ng-view>` instead), or
|
[JSON2](https://github.com/douglascrockford/JSON-js) or
|
||||||
|
[JSON3](http://bestiejs.github.com/json3/) polyfills for this.
|
||||||
|
|
||||||
2. if you **do use** custom element tags, then you must take these steps to make IE happy:
|
2. you **do not** use custom element tags such as `<ng:view>` (use the attribute version
|
||||||
|
`<div ng-view>` instead), or
|
||||||
|
|
||||||
|
3. if you **do use** custom element tags, then you must take these steps to make IE happy:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
|
|
@ -25,7 +29,7 @@ To make your angular application work on IE please make sure that:
|
||||||
document.createElement('ng-include');
|
document.createElement('ng-include');
|
||||||
document.createElement('ng-pluralize');
|
document.createElement('ng-pluralize');
|
||||||
document.createElement('ng-view');
|
document.createElement('ng-view');
|
||||||
|
|
||||||
// Optionally these for CSS
|
// Optionally these for CSS
|
||||||
document.createElement('ng:include');
|
document.createElement('ng:include');
|
||||||
document.createElement('ng:pluralize');
|
document.createElement('ng:pluralize');
|
||||||
|
|
@ -52,7 +56,7 @@ The **important** parts are:
|
||||||
|
|
||||||
# Long Version
|
# Long Version
|
||||||
|
|
||||||
IE has an issues with element tag names which are not standard HTML tag names. These fall into two
|
IE has issues with element tag names which are not standard HTML tag names. These fall into two
|
||||||
categories, and each category has its own fix.
|
categories, and each category has its own fix.
|
||||||
|
|
||||||
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
|
* If the tag name starts with `my:` prefix than it is considered an XML namespace and must
|
||||||
|
|
@ -61,13 +65,13 @@ categories, and each category has its own fix.
|
||||||
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
|
* If the tag has no `:` but it is not a standard HTML tag, then it must be pre-created using
|
||||||
`document.createElement('my-tag')`
|
`document.createElement('my-tag')`
|
||||||
|
|
||||||
* If you have are planning on styling the custom tag with CSS selectors, then it must be
|
* If you are planning on styling the custom tag with CSS selectors, then it must be
|
||||||
pre-created using `document.createElement('my-tag')` regardless of XML namespace.
|
pre-created using `document.createElement('my-tag')` regardless of XML namespace.
|
||||||
|
|
||||||
|
|
||||||
## The Good News
|
## The Good News
|
||||||
|
|
||||||
The good news is that these restrictions only apply to element tag names, and not to element
|
The good news is that these restrictions only apply to element tag names, and not to element
|
||||||
attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`.
|
attribute names. So this requires no special handling in IE: `<div my-tag your:tag></div>`.
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -84,7 +88,7 @@ result):
|
||||||
</html>
|
</html>
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
It should pares into the following DOM:
|
It should parse into the following DOM:
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
#document
|
#document
|
||||||
|
|
@ -118,12 +122,12 @@ In IE, the behavior is that the `BODY` element has three children:
|
||||||
|
|
||||||
3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have
|
3. A corrupt self closing `/mytag`. This is corrupt since element names are not allowed to have
|
||||||
the `/` character. Furthermore this closing element should not be part of the DOM since it is
|
the `/` character. Furthermore this closing element should not be part of the DOM since it is
|
||||||
only used to delimitate the structure of the DOM.
|
only used to delineate the structure of the DOM.
|
||||||
|
|
||||||
|
|
||||||
## CSS Styling of Custom Tag Names
|
## CSS Styling of Custom Tag Names
|
||||||
|
|
||||||
The to make CSS selector work with custom elements the custom element name must be shived with the
|
To make CSS selectors work with custom elements, the custom element name must be pre-created with
|
||||||
`document.createElement('my-tag')` regardless of XML namespace.
|
`document.createElement('my-tag')` regardless of XML namespace.
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
|
|
@ -133,7 +137,7 @@ The to make CSS selector work with custom elements the custom element name must
|
||||||
<script>
|
<script>
|
||||||
// needed to make ng-include parse properly
|
// needed to make ng-include parse properly
|
||||||
document.createElement('ng-include');
|
document.createElement('ng-include');
|
||||||
|
|
||||||
// needed to enable CSS reference
|
// needed to enable CSS reference
|
||||||
document.createElement('ng:view');
|
document.createElement('ng:view');
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -10,33 +10,3 @@ of the following documents before returning here to the Developer Guide:
|
||||||
|
|
||||||
* {@link misc/started Getting Started}
|
* {@link misc/started Getting Started}
|
||||||
* {@link tutorial/index Angular Tutorial}
|
* {@link tutorial/index Angular Tutorial}
|
||||||
|
|
||||||
<hr>
|
|
||||||
|
|
||||||
## {@link overview Overview of Angular}
|
|
||||||
|
|
||||||
## {@link bootstrap Initializing Angular}
|
|
||||||
|
|
||||||
## {@link dev_guide.mvc About MVC in Angular}
|
|
||||||
|
|
||||||
* {@link dev_guide.mvc.understanding_model Understanding the Model Component}
|
|
||||||
* {@link dev_guide.mvc.understanding_controller Understanding the Controller Component}
|
|
||||||
* {@link dev_guide.mvc.understanding_view Understanding the View Component}
|
|
||||||
|
|
||||||
## {@link scope Angular Scope Objects}
|
|
||||||
|
|
||||||
## {@link compiler Angular HTML Compiler}
|
|
||||||
|
|
||||||
## {@link dev_guide.templates Angular Templates}
|
|
||||||
|
|
||||||
* {@link dev_guide.templates.filters Understanding Angular Filters}
|
|
||||||
* {@link forms Understanding Angular Forms}
|
|
||||||
|
|
||||||
## {@link dev_guide.services Angular Services}
|
|
||||||
|
|
||||||
* {@link dev_guide.services.understanding_services Understanding Angular Services}
|
|
||||||
* {@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 di About Dependency Injection}
|
|
||||||
|
|
|
||||||
|
|
@ -27,15 +27,15 @@ Important things to notice:
|
||||||
* Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what
|
* Notice the reference to the `myApp` module in the `<html ng-app="myApp">`, it is what
|
||||||
bootstraps the app using your module.
|
bootstraps the app using your module.
|
||||||
|
|
||||||
<doc:example module='simpleApp'>
|
<doc:example module='myApp'>
|
||||||
<doc:source>
|
<doc:source>
|
||||||
<script>
|
<script>
|
||||||
// declare a module
|
// declare a module
|
||||||
var simpleAppModule = angular.module('simpleApp', []);
|
var simpleAppModule = angular.module('myApp', []);
|
||||||
|
|
||||||
// configure the module.
|
// configure the module.
|
||||||
// in this example we will create a greeting filter
|
// in this example we will create a greeting filter
|
||||||
simpleAppModule.filter('greet', function() {
|
myAppModule.filter('greet', function() {
|
||||||
return function(name) {
|
return function(name) {
|
||||||
return 'Hello, ' + name + '!';
|
return 'Hello, ' + name + '!';
|
||||||
};
|
};
|
||||||
|
|
@ -139,7 +139,7 @@ angular.module('myModule', []).
|
||||||
// This is an example of a run block.
|
// This is an example of a run block.
|
||||||
// You can have as many of these as you want.
|
// You can have as many of these as you want.
|
||||||
// You can only inject instances (not Providers)
|
// You can only inject instances (not Providers)
|
||||||
// int the run blocks
|
// into the run blocks
|
||||||
});
|
});
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ bootstrap auto initialize} your application.
|
||||||
|
|
||||||
We load Angular using the `<script>` tag:
|
We load Angular using the `<script>` tag:
|
||||||
|
|
||||||
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/?.?.?/angular.min.js"></script>
|
||||||
|
|
||||||
From the `ng-model` attribute of the `<input>` tags, angular automatically sets up two-way data
|
From the `ng-model` attribute of the `<input>` tags, angular automatically sets up two-way data
|
||||||
binding, and we also demonstrate some easy input validation:
|
binding, and we also demonstrate some easy input validation:
|
||||||
|
|
@ -202,7 +202,6 @@ Angular frees you from the following pain:
|
||||||
|
|
||||||
# Watch a Presentation About Angular
|
# Watch a Presentation About Angular
|
||||||
|
|
||||||
Here is an early presentation on angular, but note that substantial development has occurred since
|
Here is a presentation on Angular from May 2012.
|
||||||
the talk was given in July of 2010.
|
|
||||||
|
|
||||||
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
|
<iframe width="560" height="315" src="http://www.youtube.com/embed/bfrn5VNpwsg" frameborder="0" allowfullscreen></iframe>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ watch {@link guide/expression expressions} and propagate events.
|
||||||
## Scope as Data-Model
|
## Scope as Data-Model
|
||||||
|
|
||||||
Scope is the glue between application controller and the view. During the template {@link compiler
|
Scope is the glue between application controller and the view. During the template {@link compiler
|
||||||
linking} phase the {@link api/ng.$compileProvider.directive directives} set up
|
linking} phase the {@link api/ng.$compileProvider#directive directives} set up
|
||||||
{@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The
|
{@link api/ng.$rootScope.Scope#$watch `$watch`} expressions on the scope. The
|
||||||
`$watch` allows the directives to be notified of property changes, which allows the directive to
|
`$watch` allows the directives to be notified of property changes, which allows the directive to
|
||||||
render the updated value to the DOM.
|
render the updated value to the DOM.
|
||||||
|
|
@ -222,7 +222,7 @@ The normal flow of browser receiving an event is that it executes a correspondin
|
||||||
callback. Once the callback completes the browser re-renders the DOM and returns to waiting for
|
callback. Once the callback completes the browser re-renders the DOM and returns to waiting for
|
||||||
more events.
|
more events.
|
||||||
|
|
||||||
When the browser calls into JavaScript the code executes outside they Angular execution context,
|
When the browser calls into JavaScript the code executes outside the Angular execution context,
|
||||||
which means that Angular is unaware of model modifications. To properly process model
|
which means that Angular is unaware of model modifications. To properly process model
|
||||||
modifications the execution has to enter the Angular execution context using the {@link
|
modifications the execution has to enter the Angular execution context using the {@link
|
||||||
api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which
|
api/ng.$rootScope.Scope#$apply `$apply`} method. Only model modifications which
|
||||||
|
|
@ -231,9 +231,9 @@ directive listens on DOM events, such as {@link
|
||||||
api/ng.directive:ngClick `ng-click`} it must evaluate the
|
api/ng.directive:ngClick `ng-click`} it must evaluate the
|
||||||
expression inside the `$apply` method.
|
expression inside the `$apply` method.
|
||||||
|
|
||||||
After evaluating the expression `$apply` method performs a {@link
|
After evaluating the expression, the `$apply` method performs a {@link
|
||||||
api/ng.$rootScope.Scope#$digest `$digest`}. In $digest phase the scope examines all
|
api/ng.$rootScope.Scope#$digest `$digest`}. In the $digest phase the scope examines all
|
||||||
of the `$watch` expressions and compares them with previous value. This dirty checking, is done
|
of the `$watch` expressions and compares them with the previous value. This dirty checking is done
|
||||||
asynchronously. This means that assignment such as `$scope.username="angular"` will not
|
asynchronously. This means that assignment such as `$scope.username="angular"` will not
|
||||||
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
|
immediately cause a `$watch` to be notified, instead the `$watch` notification is delayed until
|
||||||
the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one
|
the `$digest` phase. This delay is desirable, since it coalesces multiple model updates into one
|
||||||
|
|
@ -250,13 +250,13 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||||
2. **Watcher registration**
|
2. **Watcher registration**
|
||||||
|
|
||||||
During template linking directives register {@link
|
During template linking directives register {@link
|
||||||
api/ng.$rootScope.Scope#$watch watches} on the scope. This watches will be
|
api/ng.$rootScope.Scope#$watch watches} on the scope. These watches will be
|
||||||
used to propagate model values to the DOM.
|
used to propagate model values to the DOM.
|
||||||
|
|
||||||
3. **Model mutation**
|
3. **Model mutation**
|
||||||
|
|
||||||
For mutations to be properly observed, you should make them only within the {@link
|
For mutations to be properly observed, you should make them only within the {@link
|
||||||
api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular apis do this
|
api/ng.$rootScope.Scope#$apply scope.$apply()}. (Angular APIs do this
|
||||||
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
implicitly, so no extra `$apply` call is needed when doing synchronous work in controllers,
|
||||||
or asynchronous work with {@link api/ng.$http $http} or {@link
|
or asynchronous work with {@link api/ng.$http $http} or {@link
|
||||||
api/ng.$timeout $timeout} services.
|
api/ng.$timeout $timeout} services.
|
||||||
|
|
@ -279,10 +279,10 @@ the `$digest` phase. This delay is desirable, since it coalesces multiple model
|
||||||
### Scopes and Directives
|
### Scopes and Directives
|
||||||
|
|
||||||
During the compilation phase, the {@link compiler compiler} matches {@link
|
During the compilation phase, the {@link compiler compiler} matches {@link
|
||||||
api/ng.$compileProvider.directive directives} against the DOM template. The directives
|
api/ng.$compileProvider#directive directives} against the DOM template. The directives
|
||||||
usually fall into one of two categories:
|
usually fall into one of two categories:
|
||||||
|
|
||||||
- Observing {@link api/ng.$compileProvider.directive directives}, such as
|
- Observing {@link api/ng.$compileProvider#directive directives}, such as
|
||||||
double-curly expressions `{{expression}}`, register listeners using the {@link
|
double-curly expressions `{{expression}}`, register listeners using the {@link
|
||||||
api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs
|
api/ng.$rootScope.Scope#$watch $watch()} method. This type of directive needs
|
||||||
to be notified whenever the expression changes so that it can update the view.
|
to be notified whenever the expression changes so that it can update the view.
|
||||||
|
|
@ -299,7 +299,7 @@ correctly.
|
||||||
|
|
||||||
### Directives that Create Scopes
|
### Directives that Create Scopes
|
||||||
|
|
||||||
In most cases, {@link api/ng.$compileProvider.directive directives} and scopes interact
|
In most cases, {@link api/ng.$compileProvider#directive directives} and scopes interact
|
||||||
but do not create new instances of scope. However, some directives, such as {@link
|
but do not create new instances of scope. However, some directives, such as {@link
|
||||||
api/ng.directive:ngController ng-controller} and {@link
|
api/ng.directive:ngController ng-controller} and {@link
|
||||||
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
|
api/ng.directive:ngRepeat ng-repeat}, create new child scopes
|
||||||
|
|
|
||||||
|
|
@ -4,54 +4,68 @@
|
||||||
|
|
||||||
#FAQ
|
#FAQ
|
||||||
|
|
||||||
### Why is this project called "angular"? Why is the namespace called "ng"?
|
### Why is this project called "AngularJS"? Why is the namespace called "ng"?
|
||||||
|
|
||||||
Because HTML has angular brackets and "ng" sounds like "angular".
|
Because HTML has Angular brackets and "ng" sounds like "Angular".
|
||||||
|
|
||||||
### Is <angular/> an HTML5 tag?
|
|
||||||
|
|
||||||
No, <angular/> is not an HTML5 tag. angular is an orthogonal project to HTML5; you can use the two
|
### Is AngularJS a library, framework, plugin or a browser extension?
|
||||||
together.
|
|
||||||
|
|
||||||
### Is angular a {library, framework, DOM manipulation library, widget library, native plugin}?
|
AngularJS fits the definition of a framework the best, even though it's much more lightweight than
|
||||||
|
a typical framework and that's why many confuse it with a library.
|
||||||
|
|
||||||
No, angular is none of these. You don't call its functions, it does not call your functions,
|
AngularJS is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
|
||||||
it does not provide a way to manipulate DOM, but does provide primitives to create UI projections
|
So it's definitely not a plugin or some other native browser extension.
|
||||||
of your data. There are lots of existing widget libraries which you can integrate with angular.
|
|
||||||
It is 100% JavaScript, 100% client side and compatible with both desktop and mobile browsers.
|
|
||||||
|
|
||||||
### Do I need to worry about security holes in angular?
|
|
||||||
|
|
||||||
Like with any technology, angular is not impervious to attack. angular does, however, provide
|
### Is AngularJS a templating system?
|
||||||
built-in protection from basic security holes including cross-site scripting and HTML injection
|
|
||||||
attacks. angular does round-trip escaping on all strings for you.
|
|
||||||
|
|
||||||
### Can I download the source, build, and host the angular environment locally?
|
At the highest level, Angular does look like a just another templating system. But there is one
|
||||||
|
important reason why Angular templating system is different and makes it very good fit for
|
||||||
Yes. See instructions in {@link downloading}.
|
application development: bidirectional data binding. The template is compiled in the browser and
|
||||||
|
the compilation step produces a live view. This means you, the developers, don't need to write
|
||||||
### Is angular a templating system?
|
|
||||||
|
|
||||||
At the highest level, angular does look like a just another templating system. But there is one
|
|
||||||
important reason why angular templating system is different and makes it very good fit for
|
|
||||||
application development: bidirectional data binding. The template is compiled on the browser and
|
|
||||||
the compilation step produces a live view. This means you, the developer, don't need to write
|
|
||||||
code to constantly sync the view with the model and the model with the view as in other
|
code to constantly sync the view with the model and the model with the view as in other
|
||||||
templating systems.
|
templating systems.
|
||||||
|
|
||||||
|
|
||||||
|
### Do I need to worry about security holes in AngularJS?
|
||||||
|
|
||||||
|
Like with any technology, AngularJS is not impervious to attack. angular does, however, provide
|
||||||
|
built-in protection from basic security holes including cross-site scripting and HTML injection
|
||||||
|
attacks. AngularJS does round-trip escaping on all strings for you and even offers XSRF protection
|
||||||
|
for server-side communication.
|
||||||
|
|
||||||
|
AngularJS was designed to be compatible with other security measures like Content Security Policy
|
||||||
|
(CSP), HTTPS (SSL/TLS) and server-side authentication and authorization that greatly reduce the
|
||||||
|
possible attack vectors and we highly recommended their use.
|
||||||
|
|
||||||
|
|
||||||
|
### Can I download the source, build, and host the AngularJS environment locally?
|
||||||
|
|
||||||
|
Yes. See instructions in {@link downloading}.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What browsers does angular work with?
|
### What browsers does angular work with?
|
||||||
|
|
||||||
Webkit-based browsers (Safari, Chrome, iPhone, Android, WebOS, BlackBerry 6), Firefox, IE6 and
|
Our we run our extensive test suite against the following browsers: Safari, Chrome, Firefox, Opera,
|
||||||
above. Note that CSS only works on IE7 and above.
|
IE8, IE9 and mobile browsers (Android, Chrome Mobile, iOS Safari).
|
||||||
|
|
||||||
### What's angular's performance like?
|
|
||||||
|
|
||||||
angular takes ~300ms to load, render, and compile. In Chrome it uses about 2-5MB of memory. Your
|
### What's Angular's performance like?
|
||||||
app's performance will vary depending on how many bindings you use.
|
|
||||||
|
|
||||||
### How big is the angular bootstrap JS file that I need to include?
|
The startup time heavily depends on your network connection, state of the cache, browser used and
|
||||||
|
available hardware, but typically we measure bootstrap time in tens or hundreds of milliseconds.
|
||||||
|
|
||||||
|
The runtime performance will vary depending on the number and complexity of bindings on the page
|
||||||
|
as well as the speed of your backend (for apps that fetch data from the backend). Just for an
|
||||||
|
illustration we typically build snappy apps with hundreds or thousands of active bindings.
|
||||||
|
|
||||||
|
|
||||||
|
### How big is the angular.js file that I need to include?
|
||||||
|
|
||||||
|
The size of the file is < 29KB compressed and minified.
|
||||||
|
|
||||||
The size of the library itself is < 50KB compressed and obfuscated.
|
|
||||||
|
|
||||||
### Can I use the open-source Closure Library with angular?
|
### Can I use the open-source Closure Library with angular?
|
||||||
|
|
||||||
|
|
@ -60,22 +74,25 @@ in angular.
|
||||||
|
|
||||||
### Does angular use the jQuery library?
|
### Does angular use the jQuery library?
|
||||||
|
|
||||||
Yes, angular uses {@link http://jquery.com/ jQuery}, the open source DOM manipulation library.
|
Yes, Angular can use {@link http://jquery.com/ jQuery} if it's present in your app when the
|
||||||
If jQuery is not present in your script path, angular falls back on its own implementation of
|
application is being bootstrapped. If jQuery is not present in your script path, Angular falls back
|
||||||
{@link api/angular.element jQuery lite}. If jQuery is present in the path, angular uses it to
|
to its own implementation of the subset of jQuery that we call {@link api/angular.element jQLite}.
|
||||||
manipulate the DOM.
|
|
||||||
|
|
||||||
### What is testability like in angular?
|
### What is testability like in angular?
|
||||||
|
|
||||||
Very testable. It has an integrated dependency injection framework. See
|
Very testable and designed this way from ground up. It has an integrated dependency injection
|
||||||
|
framework, provides mocks for many heavy dependencies (server-side communication). See
|
||||||
{@link api/ng service} for details.
|
{@link api/ng service} for details.
|
||||||
|
|
||||||
|
|
||||||
### How can I learn more about angular?
|
### How can I learn more about angular?
|
||||||
|
|
||||||
Watch the July 28, 2010 talk
|
Watch the July 28, 2010 talk
|
||||||
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
"{@link http://www.youtube.com/watch?v=elvcgVSynRg| Angular: A Radically Different Way of Building
|
||||||
AJAX Apps}".
|
AJAX Apps}".
|
||||||
|
|
||||||
|
|
||||||
### How is angular licensed?
|
### How is angular licensed?
|
||||||
|
|
||||||
The MIT License.
|
The MIT License.
|
||||||
|
|
|
||||||
|
|
@ -2,142 +2,37 @@
|
||||||
@name Getting Started
|
@name Getting Started
|
||||||
@description
|
@description
|
||||||
|
|
||||||
# Hello World!
|
We want you to have an easy time while starting to use Angular. We've put together the following steps on your path to
|
||||||
|
becoming an Angular expert.
|
||||||
|
|
||||||
A great way for you to get started with AngularJS is to create the tradtional
|
1. Read the {@link guide/concepts conceptual overview}.<br/>Understand Angular's vocabulary and how all the Angular
|
||||||
"Hello World!" app:
|
components work together.
|
||||||
|
1. Do the {@link tutorial/ AngularJS Tutorial}.<br/>Walk end-to-end through building and application complete with tests
|
||||||
1. In your favorite text editor, create an HTML file
|
on top of a node.js web server. Covers every major AngularJS feature and show you how to set up your development
|
||||||
(for example, `helloworld.html`).
|
environment.
|
||||||
2. From the __Source__ box below, copy and paste the code into your HTML file.
|
1. Download or clone the {@link https://github.com/angular/angular-seed Seed App project template}.<br/>Gives you a
|
||||||
(Double-click on the source to easily select all.)
|
starter app with a directory layout, test harness, and scripts to begin building your application.
|
||||||
3. Open the file in your web browser.
|
|
||||||
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
Hello {{'World'}}!
|
|
||||||
</doc:source>
|
|
||||||
</doc:example>
|
|
||||||
|
|
||||||
The resulting web page should look something like the following:
|
|
||||||
|
|
||||||
<img class="center" src="img/helloworld.png" border="1">
|
|
||||||
|
|
||||||
Now let's take a closer look at that code, and see what is going on behind
|
|
||||||
the scenes.
|
|
||||||
|
|
||||||
The `ng-app` tags tells angular to process the entire HTML page and bootstrap the app when the page
|
|
||||||
is loaded:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<html ng-app>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
The next line downloads the angular script:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
<script src="http://code.angularjs.org/angular-?.?.?.min.js"></script>
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
(For details on what happens when angular processes an HTML page,
|
|
||||||
see {@link guide/bootstrap Bootstrap}.)
|
|
||||||
|
|
||||||
Finally, this line in the `<body>` of the page is the template that describes
|
|
||||||
how to display our greeting in the UI:
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
Hello {{'World'}}!
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
Note the use of the double curly brace markup (`{{ }}`) to bind the expression to
|
|
||||||
the greeting text. Here the expression is the string literal 'World'.
|
|
||||||
|
|
||||||
Next let's look at a more interesting example, that uses AngularJS to
|
|
||||||
bind a dynamic expression to our greeting text.
|
|
||||||
|
|
||||||
# Hello AngularJS World!
|
|
||||||
|
|
||||||
This example demonstrates angular's two-way data binding:
|
|
||||||
|
|
||||||
1. Edit the HTML file you created in the "Hello World!" example above.
|
|
||||||
2. Replace the contents of `<body>` with the code from the __Source__ box below.
|
|
||||||
3. Refresh your browser window.
|
|
||||||
|
|
||||||
<doc:example>
|
|
||||||
<doc:source>
|
|
||||||
Your name: <input type="text" ng-model="yourname" placeholder="World">
|
|
||||||
<hr>
|
|
||||||
Hello {{yourname || 'World'}}!
|
|
||||||
</doc:source>
|
|
||||||
</doc:example>
|
|
||||||
|
|
||||||
After the refresh, the page should look something like this:
|
|
||||||
|
|
||||||
<img class="left" src="img/helloworld_2way.png" border="1" >
|
|
||||||
|
|
||||||
These are some of the important points to note from this example:
|
|
||||||
|
|
||||||
* The text input {@link guide/directive directive}
|
|
||||||
is bound to a model variable called `yourname`.
|
|
||||||
* The double curly braces notation binds the `yourname` model to the greeting text.
|
|
||||||
|
|
||||||
* You did not need to explicitly register an event listener or define an event handler for events!
|
|
||||||
|
|
||||||
Now try typing your name into the input box, and notice the immediate change to
|
|
||||||
the displayed greeting. This demonstrates the concept of angular's
|
|
||||||
{@link guide/dev_guide.templates.databinding bi-directional data binding}. Any changes to the input
|
|
||||||
field are immediately
|
|
||||||
reflected in the model (one direction), and any changes to the model are
|
|
||||||
reflected in the greeting text (the other direction).
|
|
||||||
|
|
||||||
|
|
||||||
# Anatomy Of An Angular App
|
#Further Steps
|
||||||
|
|
||||||
This section describes the 3 parts of an angular app, and explains how they map to the
|
##Watch Videos
|
||||||
Model-View-Controller design pattern:
|
|
||||||
|
|
||||||
## Templates
|
If you haven’t had a chance to watch the videos from the homepage, please check out:
|
||||||
|
* {@link http://www.youtube.com/watch?v=WuiHuZq_cg4&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Introduction to AngularJS}
|
||||||
|
* {@link http://www.youtube.com/watch?v=Yg-R1gchccg&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Creating Directives}
|
||||||
|
* {@link http://www.youtube.com/watch?v=IRelx4-ISbs&list=PL173F1A311439C05D&context=C48ac877ADvjVQa1PpcFONnl4Q5x8hqvT6tRBTE-m0-Ym47jO3PEE%3D Communicating with Servers}
|
||||||
|
|
||||||
Templates, which you write in HTML and CSS, serve as the View. You add elements, attributes, and
|
And visit our {@link http://www.youtube.com/user/angularjs YouTube channel} for more AngularJS video presentations and
|
||||||
markup to HTML, which serve as instructions to the angular compiler. The angular compiler is fully
|
tutorials.
|
||||||
extensible, meaning that with angular you can build your own declarative language on top of HTML!
|
|
||||||
|
|
||||||
|
##Subscribe
|
||||||
|
|
||||||
## Application Logic and Behavior
|
* Subscribe to the {@link http://groups.google.com/forum/?fromgroups#!forum/angular mailing list}. Ask questions here!
|
||||||
|
* Follow us on {@link https://twitter.com/intent/follow?original_referer=http%3A%2F%2Fangularjs.org%2F®ion=follow_link&screen_name=angularjs&source=followbutton&variant=2.0 Twitter}
|
||||||
|
* Add us to your circles on {@link https://plus.google.com/110323587230527980117/posts Google+}
|
||||||
|
|
||||||
Application Logic and Behavior, which you define in JavaScript, serve as the Controller. With
|
##Read more
|
||||||
angular (unlike with standard AJAX applications) you don't need to write additional listeners or
|
|
||||||
DOM manipulators, because they are built-in. This feature makes your application logic very easy to
|
|
||||||
write, test, maintain, and understand.
|
|
||||||
|
|
||||||
|
The AngularJS documentation includes the {@link guide/index Developer Guide} covering concepts and the
|
||||||
## Data
|
{@link api/ API Reference} for syntax and usage.
|
||||||
|
|
||||||
The Model is referenced from properties on {@link guide/scope angular scope objects}.
|
|
||||||
The data in your model could be Javascript objects, arrays, or primitives, it doesn't matter. What
|
|
||||||
matters is that these are all referenced by the scope object.
|
|
||||||
|
|
||||||
Angular employs scopes to keep your data model and your UI in sync. Whenever something occurs to
|
|
||||||
change the state of the model, angular immediately reflects that change in the UI, and vice versa.
|
|
||||||
|
|
||||||
The following illustration shows the parts of an angular application and how they work together:
|
|
||||||
|
|
||||||
<img class="left" src="img/angular_parts.png" border="0" />
|
|
||||||
|
|
||||||
In addition, angular comes with a set of Services, which have the following properties:
|
|
||||||
|
|
||||||
* The services provided are very useful for building web applications.
|
|
||||||
* You can extend and add application-specific behavior to services.
|
|
||||||
* Services include Dependency-Injection, XHR, caching, URL routing, and browser abstraction.
|
|
||||||
|
|
||||||
|
|
||||||
# Where To Go Next
|
|
||||||
|
|
||||||
* If you like what you've learned so far, you should definitely check out our awesome {@link
|
|
||||||
tutorial/ Tutorial}, which walks you through the process of building real apps with AngularJS.
|
|
||||||
|
|
||||||
* For further explanations and examples of the AngularJS concepts presented on this page, see the
|
|
||||||
{@link guide/index Developer Guide}.
|
|
||||||
|
|
||||||
* For additional hands-on examples of using AngularJS, including more source code that you can
|
|
||||||
copy and paste into your own pages, take a look through the {@link cookbook/ Cookbook}.
|
|
||||||
|
|
|
||||||
|
|
@ -173,10 +173,11 @@ __`app/index.html`:__
|
||||||
|
|
||||||
<html ng-app>
|
<html ng-app>
|
||||||
|
|
||||||
The `ng-app` attribute is represents an Angular directive used to flag an element which Angular
|
The `ng-app` attribute is represents an Angular directive (named `ngApp`; Angular uses
|
||||||
should consider to be the root element of our application. This gives application developers the
|
`name-with-dashes` for attribute names and `camelCase` for the corresponding directive name)
|
||||||
freedom to tell Angular if the entire html page or only a portion of it should be treated as the
|
used to flag an element which Angular should consider to be the root element of our application.
|
||||||
Angular application.
|
This gives application developers the freedom to tell Angular if the entire html page or only a
|
||||||
|
portion of it should be treated as the Angular application.
|
||||||
|
|
||||||
* AngularJS script tag:
|
* AngularJS script tag:
|
||||||
|
|
||||||
|
|
@ -195,7 +196,7 @@ being the element on which the `ngApp` directive was defined.
|
||||||
This line demonstrates the core feature of Angular's templating capabilities – a binding, denoted
|
This line demonstrates the core feature of Angular's templating capabilities – a binding, denoted
|
||||||
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
|
by double-curlies `{{ }}` as well as a simple expression `'yet' + '!'` used in this binding.
|
||||||
|
|
||||||
The binding tells Angular, that it should evaluate an expression and insert the result into the
|
The binding tells Angular that it should evaluate an expression and insert the result into the
|
||||||
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
|
DOM in place of the binding. Rather than a one-time insert, as we'll see in the next steps, a
|
||||||
binding will result in efficient continuous updates whenever the result of the expression
|
binding will result in efficient continuous updates whenever the result of the expression
|
||||||
evaluation changes.
|
evaluation changes.
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ __`app/index.html`:__
|
||||||
|
|
||||||
We added a standard HTML `<input>` tag and used angular's
|
We added a standard HTML `<input>` tag and used angular's
|
||||||
{@link api/ng.filter:filter $filter} function to process the input for the
|
{@link api/ng.filter:filter $filter} function to process the input for the
|
||||||
`ngRepeat` directive.
|
{@link api/ng.directive:ngRepeat ngRepeat} directive.
|
||||||
|
|
||||||
This lets a user enter search criteria and immediately see the effects of their search on the phone
|
This lets a user enter search criteria and immediately see the effects of their search on the phone
|
||||||
list. This new code demonstrates the following:
|
list. This new code demonstrates the following:
|
||||||
|
|
@ -176,12 +176,14 @@ ngBindTemplate} directives, which are invisible to the user while the page is lo
|
||||||
|
|
||||||
Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test
|
Refresh the browser tab with the end-to-end test runner to see the test fail. To make the test
|
||||||
pass, edit the `index.html` template to add a `div` or `p` element with `id` `"status"` and content
|
pass, edit the `index.html` template to add a `div` or `p` element with `id` `"status"` and content
|
||||||
with the `query` binding.
|
with the `query` binding, prefixed by "Current filter:". For instance:
|
||||||
|
|
||||||
* Add a `pause()` statement into an end-to-end test and rerun it. You'll see the runner pause; this
|
<div id="status">Current filter: {{query}}</div>
|
||||||
gives you the opportunity to explore the state of your application while it is displayed in the
|
|
||||||
browser. The app is live! You can change the search query to prove it. Notice how useful this is
|
* Add a `pause()` statement inside of an end-to-end test and rerun it. You'll see the runner pause;
|
||||||
for troubleshooting end-to-end tests.
|
this gives you the opportunity to explore the state of your application while it is displayed in
|
||||||
|
the browser. The app is live! You can change the search query to prove it. Notice how useful this
|
||||||
|
is for troubleshooting end-to-end tests.
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,7 @@ necessary!
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneListCtrl($scope) {
|
function PhoneListCtrl($scope) {
|
||||||
$scope.phones = [
|
$scope.phones = [
|
||||||
|
|
@ -103,7 +103,7 @@ to the model.
|
||||||
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
The changes we made should be verified with both a unit test and an end-to-end test. Let's look at
|
||||||
the unit test first.
|
the unit test first.
|
||||||
|
|
||||||
__`test/unit/controllerSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
describe('PhoneCat controllers', function() {
|
describe('PhoneCat controllers', function() {
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ GitHub}:
|
||||||
|
|
||||||
## Data
|
## Data
|
||||||
|
|
||||||
The `app/phones/phone.json` file in your project is a dataset that contains a larger list of phones
|
The `app/phones/phones.json` file in your project is a dataset that contains a larger list of phones
|
||||||
stored in the JSON format.
|
stored in the JSON format.
|
||||||
|
|
||||||
Following is a sample of the file:
|
Following is a sample of the file:
|
||||||
|
|
@ -104,7 +104,7 @@ to avoid any possible naming collisions.
|
||||||
Since angular infers the controller's dependencies from the names of arguments to the controller's
|
Since angular infers the controller's dependencies from the names of arguments to the controller's
|
||||||
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
|
constructor function, if you were to {@link http://en.wikipedia.org/wiki/Minification_(programming)
|
||||||
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
minify} the JavaScript code for `PhoneListCtrl` controller, all of its function arguments would be
|
||||||
minified as well, and the dependency injector would be able to identify services correctly.
|
minified as well, and the dependency injector would not be able to identify services correctly.
|
||||||
|
|
||||||
To overcome issues caused by minification, just assign an array with service identifier strings
|
To overcome issues caused by minification, just assign an array with service identifier strings
|
||||||
into the `$inject` property of the controller function, just like the last line in the snippet
|
into the `$inject` property of the controller function, just like the last line in the snippet
|
||||||
|
|
@ -164,8 +164,8 @@ isolated from the work done in other tests.
|
||||||
|
|
||||||
* We created a new scope for our controller by calling `$rootScope.$new()`
|
* We created a new scope for our controller by calling `$rootScope.$new()`
|
||||||
|
|
||||||
* We called `scope.$new(PhoneListCtrl)` to get Angular to create the child scope associated with
|
* We called the injected `$controller` function passing the `PhoneListCtrl` function and the created
|
||||||
the `PhoneListCtrl` controller.
|
scope as parameters.
|
||||||
|
|
||||||
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
Because our code now uses the `$http` service to fetch the phone list data in our controller, before
|
||||||
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
we create the `PhoneListCtrl` child scope, we need to tell the testing harness to expect an
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ api/ng.directive:ngSrc ngSrc} directive. That directive prevents the
|
||||||
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
|
browser from treating the angular `{{ expression }}` markup literally, and initiating a request to
|
||||||
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
|
invalid url `http://localhost:8000/app/{{phone.imageUrl}}`, which it would have done if we had only
|
||||||
specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`).
|
specified an attribute binding in a regular `src` attribute (`<img class="diagram" src="{{phone.imageUrl}}">`).
|
||||||
Using `ngSrc` (`ng-src`) prevents the browser from making an http request to an invalid location.
|
Using the `ngSrc` directive prevents the browser from making an http request to an invalid location.
|
||||||
|
|
||||||
|
|
||||||
## Test
|
## Test
|
||||||
|
|
@ -87,7 +87,8 @@ views that we will implement in the upcoming steps.
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||||
can see them running on {@link
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-6/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
@ -96,11 +97,15 @@ or Chrome's Web Inspector, or inspecting the webserver access logs, confirm that
|
||||||
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
|
making an extraneous request to `/app/%7B%7Bphone.imageUrl%7D%7D` (or
|
||||||
`/app/{{phone.imageUrl}}`).
|
`/app/{{phone.imageUrl}}`).
|
||||||
|
|
||||||
|
The issue here is that the browser will fire a request for that invalid image address as soon as
|
||||||
|
it hits the `img` tag, which is before Angular has a chance to evaluate the expression and inject
|
||||||
|
the valid address.
|
||||||
|
|
||||||
|
|
||||||
# Summary
|
# Summary
|
||||||
|
|
||||||
Now that you have added phone images and links, go to {@link step_07 step 7} to learn about angular
|
Now that you have added phone images and links, go to {@link step_07 step 7} to learn about Angular
|
||||||
layout templates and how angular makes it easy to create applications that have multiple views.
|
layout templates and how Angular makes it easy to create applications that have multiple views.
|
||||||
|
|
||||||
|
|
||||||
<ul doc-tutorial-nav="6"></ul>
|
<ul doc-tutorial-nav="6"></ul>
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ detail page is displayed.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-6...step-7
|
https://github.com/angular/angular-phonecat/compare/step-6...step-7
|
||||||
GitHub}:
|
GitHub}.
|
||||||
|
|
||||||
|
|
||||||
## Multiple Views, Routing and Layout Template
|
## Multiple Views, Routing and Layout Template
|
||||||
|
|
@ -114,14 +114,14 @@ directive:
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html ng-app="phonecat">
|
<html lang="en" ng-app="phonecat">
|
||||||
...
|
...
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
## Controllers
|
## Controllers
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
function PhoneDetailCtrl($scope, $routeParams) {
|
function PhoneDetailCtrl($scope, $routeParams) {
|
||||||
|
|
@ -140,11 +140,12 @@ route into the layout template, which makes it a perfect fit for our `index.html
|
||||||
|
|
||||||
__`app/index.html`:__
|
__`app/index.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<html ng-app="phonecat">
|
<html lang="en" ng-app="phonecat">
|
||||||
<head>
|
<head>
|
||||||
...
|
...
|
||||||
<script src="lib/angular/angular.js"></script>
|
<script src="lib/angular/angular.js"></script>
|
||||||
<script src="js/app.js"></script>
|
<script src="js/app.js"></script>
|
||||||
|
<script src="js/controllers.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
|
|
@ -234,7 +235,7 @@ to various URLs and verify that the correct view was rendered.
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||||
can see them running on {@link
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-7/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ Now when you click on a phone on the list, the phone details page with phone-spe
|
||||||
is displayed.
|
is displayed.
|
||||||
|
|
||||||
To implement the phone details view we will use {@link api/ng.$http $http} to fetch
|
To implement the phone details view we will use {@link api/ng.$http $http} to fetch
|
||||||
our data, and we'll flesh out the `phone-details.html` view template.
|
our data, and we'll flesh out the `phone-detail.html` view template.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-7...step-8
|
https://github.com/angular/angular-phonecat/compare/step-7...step-8
|
||||||
|
|
@ -59,7 +59,7 @@ show this data in the phone detail view.
|
||||||
We'll expand the `PhoneDetailCtrl` by using the `$http` service to fetch the json files. This works
|
We'll expand the `PhoneDetailCtrl` by using the `$http` service to fetch the json files. This works
|
||||||
the same way as the phone list controller.
|
the same way as the phone list controller.
|
||||||
|
|
||||||
__`app/js/controller.js`:__
|
__`app/js/controllers.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
function PhoneDetailCtrl($scope, $routeParams, $http) {
|
function PhoneDetailCtrl($scope, $routeParams, $http) {
|
||||||
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
$http.get('phones/' + $routeParams.phoneId + '.json').success(function(data) {
|
||||||
|
|
@ -81,7 +81,7 @@ Note where we use the angular `{{expression}}` markup and `ngRepeat` to project
|
||||||
our model into the view.
|
our model into the view.
|
||||||
|
|
||||||
|
|
||||||
__`app/partials/phone-details.html`:__
|
__`app/partials/phone-detail.html`:__
|
||||||
<pre>
|
<pre>
|
||||||
<img ng-src="{{phone.images[0]}}" class="phone">
|
<img ng-src="{{phone.images[0]}}" class="phone">
|
||||||
|
|
||||||
|
|
@ -121,7 +121,7 @@ TODO!
|
||||||
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
|
We wrote a new unit test that is similar to the one we wrote for the `PhoneListCtrl` controller in
|
||||||
step 5.
|
step 5.
|
||||||
|
|
||||||
__`test/unit/controllerSpec.js`:__
|
__`test/unit/controllersSpec.js`:__
|
||||||
<pre>
|
<pre>
|
||||||
...
|
...
|
||||||
describe('PhoneDetailCtrl', function(){
|
describe('PhoneDetailCtrl', function(){
|
||||||
|
|
@ -180,7 +180,7 @@ __`test/e2e/scenarios.js`:__
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||||
can see them running on {@link
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ Navigate to one of the detail pages.
|
||||||
|
|
||||||
In the previous step, the details page displayed either "true" or "false" to indicate whether
|
In the previous step, the details page displayed either "true" or "false" to indicate whether
|
||||||
certain phone features were present or not. We have used a custom filter to convert those text
|
certain phone features were present or not. We have used a custom filter to convert those text
|
||||||
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see, what the filter code looks like.
|
strings into glyphs: ✓ for "true", and ✘ for "false". Let's see what the filter code looks like.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-8...step-9
|
https://github.com/angular/angular-phonecat/compare/step-8...step-9
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ In this step, you will add a clickable phone image swapper to the phone details
|
||||||
|
|
||||||
The phone details view displays one large image of the current phone and several smaller thumbnail
|
The phone details view displays one large image of the current phone and several smaller thumbnail
|
||||||
images. It would be great if we could replace the large image with any of the thumbnails just by
|
images. It would be great if we could replace the large image with any of the thumbnails just by
|
||||||
clicking on the desired thumbnail image. Let's have a look at how we can do this with angular.
|
clicking on the desired thumbnail image. Let's have a look at how we can do this with Angular.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
https://github.com/angular/angular-phonecat/compare/step-9...step-10
|
https://github.com/angular/angular-phonecat/compare/step-9...step-10
|
||||||
|
|
@ -105,7 +105,7 @@ __`test/e2e/scenarios.js`:__
|
||||||
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
You can now refresh the browser tab with the end-to-end test runner to see the tests run, or you
|
||||||
can see them running on {@link
|
can see them running on {@link
|
||||||
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
http://angular.github.com/angular-phonecat/step-8/test/e2e/runner.html
|
||||||
angular's server}.
|
Angular's server}.
|
||||||
|
|
||||||
# Experiments
|
# Experiments
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ In this step, you will improve the way our app fetches data.
|
||||||
|
|
||||||
The last improvement we will make to our app is to define a custom service that represents a {@link
|
The last improvement we will make to our app is to define a custom service that represents a {@link
|
||||||
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
http://en.wikipedia.org/wiki/Representational_State_Transfer RESTful} client. Using this client we
|
||||||
can make xhr requests for data in an easier way, without having to deal with the lower-level {@link
|
can make XHR requests for data in an easier way, without having to deal with the lower-level {@link
|
||||||
api/ng.$http $http} API, HTTP methods and URLs.
|
api/ng.$http $http} API, HTTP methods and URLs.
|
||||||
|
|
||||||
The most important changes are listed below. You can see the full diff on {@link
|
The most important changes are listed below. You can see the full diff on {@link
|
||||||
|
|
@ -57,13 +57,22 @@ The {@link api/ngResource.$resource `$resource`} service makes it easy to create
|
||||||
lines of code. This client can then be used in our application, instead of the lower-level {@link
|
lines of code. This client can then be used in our application, instead of the lower-level {@link
|
||||||
api/ng.$http $http} service.
|
api/ng.$http $http} service.
|
||||||
|
|
||||||
|
__`app/js/app.js`.__
|
||||||
|
<pre>
|
||||||
|
...
|
||||||
|
angular.module('phonecat', ['phonecatFilters', 'phonecatServices']).
|
||||||
|
...
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
We need to add 'phonecatServices' to 'phonecat' application's requires array.
|
||||||
|
|
||||||
|
|
||||||
## Controller
|
## Controller
|
||||||
|
|
||||||
We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
|
We simplified our sub-controllers (`PhoneListCtrl` and `PhoneDetailCtrl`) by factoring out the
|
||||||
lower-level {@link api/ng.$http $http} service, replacing it with a new service called
|
lower-level {@link api/ng.$http $http} service, replacing it with a new service called
|
||||||
`Phone`. Angular's {@link api/ngResource.$resource `$resource`} service is easier to
|
`Phone`. Angular's {@link api/ngResource.$resource `$resource`} service is easier to
|
||||||
use than `$http for interacting with data sources exposed as RESTful resources. It is also easier
|
use than `$http` for interacting with data sources exposed as RESTful resources. It is also easier
|
||||||
now to understand what the code in our controllers is doing.
|
now to understand what the code in our controllers is doing.
|
||||||
|
|
||||||
__`app/js/controllers.js`.__
|
__`app/js/controllers.js`.__
|
||||||
|
|
@ -107,8 +116,8 @@ This is a simple statement that we want to query for all phones.
|
||||||
An important thing to notice in the code above is that we don't pass any callback functions when
|
An important thing to notice in the code above is that we don't pass any callback functions when
|
||||||
invoking methods of our Phone service. Although it looks as if the result were returned
|
invoking methods of our Phone service. Although it looks as if the result were returned
|
||||||
synchronously, that is not the case at all. What is returned synchronously is a "future" — an
|
synchronously, that is not the case at all. What is returned synchronously is a "future" — an
|
||||||
object, which will be filled with data when the xhr response returns. Because of the data-binding
|
object, which will be filled with data when the XHR response returns. Because of the data-binding
|
||||||
in angular, we can use this future and bind it to our template. Then, when the data arrives, the
|
in Angular, we can use this future and bind it to our template. Then, when the data arrives, the
|
||||||
view will automatically update.
|
view will automatically update.
|
||||||
|
|
||||||
Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
|
Sometimes, relying on the future object and data-binding alone is not sufficient to do everything
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ For more details and examples of the Angular concepts we touched on in this tuto
|
||||||
For several more examples of code, see the {@link cookbook/ Cookbook}.
|
For several more examples of code, see the {@link cookbook/ Cookbook}.
|
||||||
|
|
||||||
When you are ready to start developing a project using Angular, we recommend that you bootstrap
|
When you are ready to start developing a project using Angular, we recommend that you bootstrap
|
||||||
your development with the {@link https://github.com/angular/angular-seed angular seed} project.
|
your development with the {@link https://github.com/angular/angular-seed angular-seed} project.
|
||||||
|
|
||||||
We hope this tutorial was useful to you and that you learned enough about Angular to make you want
|
We hope this tutorial was useful to you and that you learned enough about Angular to make you want
|
||||||
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your
|
to learn more. We especially hope you are inspired to go out and develop Angular web apps of your
|
||||||
|
|
|
||||||
BIN
docs/img/guide/concepts-controller.png
Normal file
|
After Width: | Height: | Size: 80 KiB |
BIN
docs/img/guide/concepts-directive.png
Normal file
|
After Width: | Height: | Size: 48 KiB |
BIN
docs/img/guide/concepts-model.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
docs/img/guide/concepts-module-injector.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
docs/img/guide/concepts-runtime.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
docs/img/guide/concepts-scope.png
Normal file
|
After Width: | Height: | Size: 78 KiB |
BIN
docs/img/guide/concepts-startup.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/img/guide/concepts-view.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
|
@ -58,10 +58,10 @@ exports.Example.prototype.addSource = function(name, content) {
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.Example.prototype.toHtml = function() {
|
exports.Example.prototype.toHtml = function() {
|
||||||
return '<h1>Source</h1>\n' +
|
return '<h2>Source</h2>\n' +
|
||||||
this.toHtmlEdit() +
|
this.toHtmlEdit() +
|
||||||
this.toHtmlTabs() +
|
this.toHtmlTabs() +
|
||||||
'<h1>Demo</h1>\n' +
|
'<h2>Demo</h2>\n' +
|
||||||
this.toHtmlEmbed();
|
this.toHtmlEmbed();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,10 @@ process.on('uncaughtException', function(err) {
|
||||||
var start = now();
|
var start = now();
|
||||||
var docs;
|
var docs;
|
||||||
|
|
||||||
writer.makeDir('build/docs/syntaxhighlighter').then(function() {
|
writer.makeDir('build/docs/', true).then(function() {
|
||||||
console.log('Generating Angular Reference Documentation...');
|
return writer.makeDir('build/docs/partials/');
|
||||||
|
}).then(function() {
|
||||||
|
console.log('Generating AngularJS Reference Documentation...');
|
||||||
return reader.collect();
|
return reader.collect();
|
||||||
}).then(function generateHtmlDocPartials(docs_) {
|
}).then(function generateHtmlDocPartials(docs_) {
|
||||||
docs = docs_;
|
docs = docs_;
|
||||||
|
|
@ -40,8 +42,10 @@ writer.makeDir('build/docs/syntaxhighlighter').then(function() {
|
||||||
function writeTheRest(writesFuture) {
|
function writeTheRest(writesFuture) {
|
||||||
var metadata = ngdoc.metadata(docs);
|
var metadata = ngdoc.metadata(docs);
|
||||||
|
|
||||||
writesFuture.push(writer.copyDir('img'));
|
writesFuture.push(writer.symlinkTemplate('css'));
|
||||||
writesFuture.push(writer.copyDir('font'));
|
writesFuture.push(writer.symlinkTemplate('font'));
|
||||||
|
writesFuture.push(writer.symlink('../../docs/img', 'build/docs/img'));
|
||||||
|
writesFuture.push(writer.symlinkTemplate('js'));
|
||||||
|
|
||||||
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
var manifest = 'manifest="/build/docs/appcache.manifest"';
|
||||||
|
|
||||||
|
|
@ -53,7 +57,7 @@ function writeTheRest(writesFuture) {
|
||||||
|
|
||||||
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq.html',
|
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq.html',
|
||||||
writer.replace, {'doc:manifest': manifest}));
|
writer.replace, {'doc:manifest': ''}));
|
||||||
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-nocache.html',
|
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-nocache.html',
|
||||||
writer.replace, {'doc:manifest': ''}));
|
writer.replace, {'doc:manifest': ''}));
|
||||||
|
|
@ -65,27 +69,27 @@ function writeTheRest(writesFuture) {
|
||||||
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-debug.html',
|
writesFuture.push(writer.copy('docs/src/templates/index.html', 'index-jq-debug.html',
|
||||||
writer.replace, {'doc:manifest': ''}));
|
writer.replace, {'doc:manifest': ''}));
|
||||||
|
|
||||||
writesFuture.push(writer.copyTpl('offline.html'));
|
writesFuture.push(writer.symlinkTemplate('offline.html'));
|
||||||
writesFuture.push(writer.copyTpl('docs-scenario.html'));
|
|
||||||
writesFuture.push(writer.copyTpl('js/jquery.min.js'));
|
|
||||||
writesFuture.push(writer.copyTpl('js/jquery.js'));
|
|
||||||
|
|
||||||
writesFuture.push(writer.output('js/docs-keywords.js',
|
writesFuture.push(writer.copyTemplate('docs-scenario.html')); // will be rewritten, don't symlink
|
||||||
|
writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs)));
|
||||||
|
|
||||||
|
writesFuture.push(writer.output('docs-keywords.js',
|
||||||
['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';']));
|
['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';']));
|
||||||
writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render()));
|
writesFuture.push(writer.output('sitemap.xml', new SiteMap(docs).render()));
|
||||||
writesFuture.push(writer.output('docs-scenario.js', ngdoc.scenarios(docs)));
|
|
||||||
writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n'));
|
writesFuture.push(writer.output('robots.txt', 'Sitemap: http://docs.angularjs.org/sitemap.xml\n'));
|
||||||
writesFuture.push(writer.output('appcache.manifest',appCache()));
|
writesFuture.push(writer.output('appcache.manifest',appCache()));
|
||||||
writesFuture.push(writer.copyTpl('.htaccess'));
|
writesFuture.push(writer.copyTemplate('.htaccess')); // will be rewritten, don't symlink
|
||||||
|
|
||||||
writesFuture.push(writer.copy('docs/src/templates/js/docs.js', 'js/docs.js'));
|
writesFuture.push(writer.symlinkTemplate('app.yaml'));
|
||||||
|
writesFuture.push(writer.symlinkTemplate('index.yaml'));
|
||||||
writesFuture.push(writer.copy('docs/src/templates/css/bootstrap.min.css', 'css/bootstrap.min.css'));
|
writesFuture.push(writer.symlinkTemplate('favicon.ico'));
|
||||||
writesFuture.push(writer.copy('docs/src/templates/css/docs.css', 'css/docs.css'));
|
writesFuture.push(writer.symlinkTemplate('main.py'));
|
||||||
writesFuture.push(writer.copy('docs/src/templates/css/font-awesome.css', 'css/font-awesome.css'));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function now() { return new Date().getTime(); }
|
function now() { return new Date().getTime(); }
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -201,7 +201,7 @@ Doc.prototype = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
flush();
|
flush();
|
||||||
this.shortName = this.name.split(/[\.:#]/).pop();
|
this.shortName = this.name.split(/[\.:#]/).pop().trim();
|
||||||
this.id = this.id || // if we have an id just use it
|
this.id = this.id || // if we have an id just use it
|
||||||
(((this.file||'').match(/.*\/([^\/]*)\.ngdoc/)||{})[1]) || // try to extract it from file name
|
(((this.file||'').match(/.*\/([^\/]*)\.ngdoc/)||{})[1]) || // try to extract it from file name
|
||||||
this.name; // default to name
|
this.name; // default to name
|
||||||
|
|
@ -451,12 +451,16 @@ Doc.prototype = {
|
||||||
dom.h('Usage', function() {
|
dom.h('Usage', function() {
|
||||||
dom.h('In HTML Template Binding', function() {
|
dom.h('In HTML Template Binding', function() {
|
||||||
dom.tag('code', function() {
|
dom.tag('code', function() {
|
||||||
dom.text('{{ ');
|
if (self.usage) {
|
||||||
dom.text(self.shortName);
|
dom.text(self.usage);
|
||||||
dom.text('_expression | ');
|
} else {
|
||||||
dom.text(self.shortName);
|
dom.text('{{ ');
|
||||||
self.parameters(dom, ':', true);
|
dom.text(self.shortName);
|
||||||
dom.text(' }}');
|
dom.text('_expression | ');
|
||||||
|
dom.text(self.shortName);
|
||||||
|
self.parameters(dom, ':', true);
|
||||||
|
dom.text(' }}');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -733,7 +737,7 @@ function metadata(docs){
|
||||||
for ( var i = 1; i < path.length; i++) {
|
for ( var i = 1; i < path.length; i++) {
|
||||||
path.splice(i, 1);
|
path.splice(i, 1);
|
||||||
}
|
}
|
||||||
var shortName = path.pop();
|
var shortName = path.pop().trim();
|
||||||
|
|
||||||
if (path.pop() == 'input') {
|
if (path.pop() == 'input') {
|
||||||
shortName = 'input [' + shortName + ']';
|
shortName = 'input [' + shortName + ']';
|
||||||
|
|
|
||||||
69
docs/src/templates/app.yaml
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
application: docs-angularjs-org
|
||||||
|
version: 1
|
||||||
|
runtime: python27
|
||||||
|
api_version: 1
|
||||||
|
threadsafe: yes
|
||||||
|
default_expiration: "2h"
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- url: /
|
||||||
|
script: main.app
|
||||||
|
|
||||||
|
- url: /appcache.manifest
|
||||||
|
static_files: appcache.manifest
|
||||||
|
upload: appcache\.manifest
|
||||||
|
|
||||||
|
- url: /docs-scenario.html
|
||||||
|
static_files: docs-scenario.html
|
||||||
|
upload: docs-scenario\.html
|
||||||
|
|
||||||
|
- url: /docs-scenario.js
|
||||||
|
static_files: docs-scenario.js
|
||||||
|
upload: docs-scenario\.js
|
||||||
|
|
||||||
|
- url: /favicon\.ico
|
||||||
|
static_files: favicon.ico
|
||||||
|
upload: favicon\.ico
|
||||||
|
|
||||||
|
- url: /docs-keywords.js
|
||||||
|
static_files: docs-keywords.js
|
||||||
|
upload: docs-keywords\.js
|
||||||
|
|
||||||
|
- url: /robots.txt
|
||||||
|
static_files: robots.txt
|
||||||
|
upload: robots\.txt
|
||||||
|
|
||||||
|
- url: /sitemap.xml
|
||||||
|
static_files: sitemap.xml
|
||||||
|
upload: sitemap\.xml
|
||||||
|
|
||||||
|
- url: /css
|
||||||
|
static_dir: css
|
||||||
|
|
||||||
|
- url: /font
|
||||||
|
static_dir: font
|
||||||
|
|
||||||
|
- url: /img
|
||||||
|
static_dir: img
|
||||||
|
|
||||||
|
- url: /js
|
||||||
|
static_dir: js
|
||||||
|
|
||||||
|
- url: /partials/(.+):(.+)
|
||||||
|
static_files: partials/\1_\2
|
||||||
|
upload: partials/.*
|
||||||
|
|
||||||
|
- url: /partials
|
||||||
|
static_dir: partials
|
||||||
|
|
||||||
|
- url: /syntaxhighlighter
|
||||||
|
static_dir: syntaxhighlighter
|
||||||
|
|
||||||
|
- url: /.*
|
||||||
|
static_files: index.html
|
||||||
|
upload: index.html
|
||||||
|
|
||||||
|
|
||||||
|
libraries:
|
||||||
|
- name: webapp2
|
||||||
|
version: "2.5.1"
|
||||||
|
|
@ -19,6 +19,11 @@ img.AngularJS-small {
|
||||||
height: 1em;
|
height: 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.icon-cog {
|
||||||
|
line-height: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
/* =============================== */
|
/* =============================== */
|
||||||
|
|
||||||
.form-search .dropdown-menu {
|
.form-search .dropdown-menu {
|
||||||
|
|
@ -140,6 +145,11 @@ ul.events > li > h3 {
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
display: block;
|
||||||
|
margin: 2em auto;
|
||||||
|
}
|
||||||
|
|
||||||
.diagram {
|
.diagram {
|
||||||
display: block;
|
display: block;
|
||||||
margin: 2em auto;
|
margin: 2em auto;
|
||||||
|
|
@ -170,3 +180,7 @@ ul.events > li > h3 {
|
||||||
color: white;
|
color: white;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.clear {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,43 @@
|
||||||
<html xmlns:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org">
|
||||||
<head>
|
<head>
|
||||||
<title>AngularJS Docs E2E Test Runner</title>
|
<title>AngularJS Docs E2E Test Runner</title>
|
||||||
<script type="text/javascript" src="../angular-scenario.js" ng:autotest></script>
|
<script>
|
||||||
<script type="text/javascript" src="docs-scenario.js"></script>
|
var gae = (location.pathname.split('/').length == 2),
|
||||||
|
headEl = document.head,
|
||||||
|
angularVersion = {
|
||||||
|
current: '"NG_VERSION_FULL"', // rewrite during build
|
||||||
|
stable: '"NG_VERSION_STABLE"'
|
||||||
|
};
|
||||||
|
|
||||||
|
addTag('script', {src: path('angular-scenario.js')}, function() {
|
||||||
|
addTag('script', {src: 'docs-scenario.js'}, function() {
|
||||||
|
angular.scenario.setUpAndRun();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function addTag(name, attributes, callback) {
|
||||||
|
var el = document.createElement(name),
|
||||||
|
attrName;
|
||||||
|
|
||||||
|
for (attrName in attributes) {
|
||||||
|
el.setAttribute(attrName, attributes[attrName]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callback) {
|
||||||
|
el.onload = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
headEl.appendChild(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function path(name) {
|
||||||
|
return gae
|
||||||
|
? 'http://code.angularjs.org/' + angularVersion.stable + '/' +
|
||||||
|
name.replace(/\.js$/, '-' + angularVersion.stable + '.js')
|
||||||
|
: '../' + name;
|
||||||
|
}
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
</body>
|
</body>
|
||||||
|
|
|
||||||
BIN
docs/src/templates/favicon.ico
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
|
|
@ -22,8 +22,13 @@
|
||||||
baseUrl = location.href.replace(rUrl, indexFile),
|
baseUrl = location.href.replace(rUrl, indexFile),
|
||||||
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
|
jQuery = /index-jq[^\.]*\.html$/.test(baseUrl),
|
||||||
debug = /index[^\.]*-debug\.html$/.test(baseUrl),
|
debug = /index[^\.]*-debug\.html$/.test(baseUrl),
|
||||||
|
gae = (baseUrl.split('/').length == 4),
|
||||||
headEl = document.getElementsByTagName('head')[0],
|
headEl = document.getElementsByTagName('head')[0],
|
||||||
sync = true;
|
sync = true,
|
||||||
|
angularVersion = {
|
||||||
|
current: '"NG_VERSION_FULL"', // rewrite during build
|
||||||
|
stable: '"NG_VERSION_STABLE"'
|
||||||
|
};
|
||||||
|
|
||||||
addTag('base', {href: baseUrl});
|
addTag('base', {href: baseUrl});
|
||||||
addTag('link', {rel: 'stylesheet', href: 'css/bootstrap.min.css', type: 'text/css'});
|
addTag('link', {rel: 'stylesheet', href: 'css/bootstrap.min.css', type: 'text/css'});
|
||||||
|
|
@ -37,9 +42,23 @@
|
||||||
addTag('script', {src: path('angular-bootstrap.js') }, sync);
|
addTag('script', {src: path('angular-bootstrap.js') }, sync);
|
||||||
addTag('script', {src: path('angular-bootstrap-prettify.js') }, sync);
|
addTag('script', {src: path('angular-bootstrap-prettify.js') }, sync);
|
||||||
addTag('script', {src: 'js/docs.js'}, sync);
|
addTag('script', {src: 'js/docs.js'}, sync);
|
||||||
addTag('script', {src: 'js/docs-keywords.js'}, sync);
|
addTag('script', {src: 'docs-keywords.js'}, sync);
|
||||||
|
|
||||||
function path(name) {
|
function path(name) {
|
||||||
|
if (gae) {
|
||||||
|
if (name.match(/^angular(-\w+)?\.js/) && !name.match(/bootstrap/)) {
|
||||||
|
name = '//ajax.googleapis.com/ajax/libs/angularjs/' +
|
||||||
|
angularVersion.stable +
|
||||||
|
'/' +
|
||||||
|
name.replace(/\.js$/, '.min.js');
|
||||||
|
} else {
|
||||||
|
name = 'http://code.angularjs.org/' +
|
||||||
|
angularVersion.stable +
|
||||||
|
'/' +
|
||||||
|
name.replace(/\.js$/, '-' + angularVersion.stable +'.min.js');
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
return '../' + name.replace(/\.js$/, debug ? '.js' : '.min.js');
|
return '../' + name.replace(/\.js$/, debug ? '.js' : '.min.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
12
docs/src/templates/index.yaml
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
indexes:
|
||||||
|
|
||||||
|
# AUTOGENERATED
|
||||||
|
|
||||||
|
# This index.yaml is automatically updated whenever the dev_appserver
|
||||||
|
# detects that a new type of query is run. If you want to manage the
|
||||||
|
# index.yaml file manually, remove the above marker line (the line
|
||||||
|
# saying "# AUTOGENERATED"). If you want to manage some indexes
|
||||||
|
# manually, move them above the marker line. The index.yaml file is
|
||||||
|
# automatically uploaded to the admin console when you next deploy
|
||||||
|
# your application using appcfg.py.
|
||||||
|
|
||||||
|
|
@ -96,7 +96,7 @@ docsApp.directive.docTutorialReset = function() {
|
||||||
' <ol>\n' +
|
' <ol>\n' +
|
||||||
' <li><p>Reset the workspace to step ' + step + '.</p>' +
|
' <li><p>Reset the workspace to step ' + step + '.</p>' +
|
||||||
' <pre>' + command + '</pre></li>\n' +
|
' <pre>' + command + '</pre></li>\n' +
|
||||||
' <li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-{{docTutorialReset}}/app">angular\'s server</a>.</p></li>\n' +
|
' <li><p>Refresh your browser or check the app out on <a href="http://angular.github.com/angular-phonecat/step-' + step + '/app">Angular\'s server</a>.</p></li>\n' +
|
||||||
' </ol>\n' +
|
' </ol>\n' +
|
||||||
' </div>\n';
|
' </div>\n';
|
||||||
}
|
}
|
||||||
|
|
|
||||||
18
docs/src/templates/main.py
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
import webapp2
|
||||||
|
from google.appengine.ext.webapp import template
|
||||||
|
|
||||||
|
|
||||||
|
class IndexHandler(webapp2.RequestHandler):
|
||||||
|
def get(self):
|
||||||
|
fragment = self.request.get('_escaped_fragment_')
|
||||||
|
|
||||||
|
if fragment:
|
||||||
|
fragment = '/partials' + fragment + '.html'
|
||||||
|
self.redirect(fragment, permanent=True)
|
||||||
|
else:
|
||||||
|
self.response.headers['Content-Type'] = 'text/html'
|
||||||
|
self.response.out.write(template.render('index-nocache.html', None))
|
||||||
|
|
||||||
|
|
||||||
|
app = webapp2.WSGIApplication([('/', IndexHandler)])
|
||||||
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
*/
|
*/
|
||||||
var qfs = require('q-fs');
|
var qfs = require('q-fs');
|
||||||
var Q = require('qq');
|
var Q = require('qq');
|
||||||
var OUTPUT_DIR = "build/docs/";
|
var OUTPUT_DIR = 'build/docs/';
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
|
||||||
exports.output = output;
|
exports.output = output;
|
||||||
|
|
@ -17,29 +17,27 @@ function output(file, content) {
|
||||||
};
|
};
|
||||||
|
|
||||||
//recursively create directory
|
//recursively create directory
|
||||||
exports.makeDir = function(path) {
|
exports.makeDir = function(p) {
|
||||||
var parts = path.split(/\//);
|
var parts = p.split(/\//);
|
||||||
var path = ".";
|
var path = ".";
|
||||||
//Sequentially create directories
|
|
||||||
var done = Q.defer();
|
|
||||||
(function createPart() {
|
|
||||||
|
|
||||||
if(!parts.length) {
|
// Recursively rebuild directory structure
|
||||||
done.resolve();
|
return qfs.exists(p).
|
||||||
} else {
|
then(function createPart(exists) {
|
||||||
path += "/" + parts.shift();
|
if(!exists && parts.length) {
|
||||||
qfs.isDirectory(path).then(function(isDir) {
|
path += "/" + parts.shift();
|
||||||
if(!isDir) {
|
return qfs.exists(path).then(function(exists) {
|
||||||
qfs.makeDirectory(path);
|
if (!exists) {
|
||||||
|
return qfs.makeDirectory(path).then(createPart, createPart);
|
||||||
|
} else {
|
||||||
|
return createPart();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
createPart();
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
})();
|
|
||||||
return done.promise;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.copyTpl = function(filename) {
|
exports.copyTemplate = function(filename) {
|
||||||
return exports.copy('docs/src/templates/' + filename, filename);
|
return exports.copy('docs/src/templates/' + filename, filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -59,8 +57,29 @@ exports.copy = function(from, to, transform) {
|
||||||
}
|
}
|
||||||
return output(to, content);
|
return output(to, content);
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
exports.symlink = symlink;
|
||||||
|
function symlink(from, to) {
|
||||||
|
return qfs.exists(to).then(function(exists) {
|
||||||
|
if (!exists) {
|
||||||
|
return qfs.symbolicLink(to, from);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
exports.symlinkTemplate = symlinkTemplate;
|
||||||
|
function symlinkTemplate(filename) {
|
||||||
|
var dest = OUTPUT_DIR + filename,
|
||||||
|
dirDepth = dest.split('/').length,
|
||||||
|
src = Array(dirDepth).join('../') + 'docs/src/templates/' + filename;
|
||||||
|
|
||||||
|
return symlink(src, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Replace placeholders in content accordingly
|
/* Replace placeholders in content accordingly
|
||||||
* @param content{string} content to be modified
|
* @param content{string} content to be modified
|
||||||
* @param replacements{obj} key and value pairs in which key will be replaced with value in content
|
* @param replacements{obj} key and value pairs in which key will be replaced with value in content
|
||||||
|
|
@ -132,3 +151,4 @@ exports.toString = function toString(obj) {
|
||||||
|
|
||||||
|
|
||||||
function noop() {};
|
function noop() {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<title>Personal Log Scenario Runner</title>
|
<title>Personal Log Scenario Runner</title>
|
||||||
|
<meta http-equiv="expires" content="0">
|
||||||
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script>
|
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng:autotest></script>
|
||||||
<script type="text/javascript" src="personalLogScenario.js"></script>
|
<script type="text/javascript" src="personalLogScenario.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
22
gen_docs.sh
|
|
@ -1,4 +1,20 @@
|
||||||
#!/bin/bash
|
#!/usr/bin/env bash
|
||||||
if [ ! -e gen_docs.disable ]; then
|
|
||||||
./node_modules/.bin/jasmine-node docs/spec --noColor && node docs/src/gen-docs.js
|
JASMINE_NODE='jasmine-node'
|
||||||
|
if ! type -p "$JASMINE_NODE" >/dev/null 2>&1;then
|
||||||
|
# Locally (npm)-installed jasmine-node
|
||||||
|
local_jasmine='./node_modules/.bin/jasmine-node'
|
||||||
|
|
||||||
|
if [[ -x "$local_jasmine" ]];then
|
||||||
|
JASMINE_NODE="$local_jasmine"
|
||||||
|
else
|
||||||
|
echo 'Could not find a locally or globally installed executable of' \
|
||||||
|
'jasmine-node. Try: `npm install jasmine-node`.' >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ ! -e gen_docs.disable ]]; then
|
||||||
|
echo 'Testing, then building documentation...'
|
||||||
|
"$JASMINE_NODE" docs/spec --noColor && node docs/src/gen-docs.js
|
||||||
fi
|
fi
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<html xmlns:ng="http://angularjs.org" wiki:ng="http://angularjs.org">
|
<html xmlns:ng="http://angularjs.org" wiki:ng="http://angularjs.org">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="expires" content="0">
|
||||||
<title><angular/> Docs Scenario Runner</title>
|
<title><angular/> Docs Scenario Runner</title>
|
||||||
<script type="text/javascript" src="../../build/angular-scenario.js" ng:autotest></script>
|
<script type="text/javascript" src="../../build/angular-scenario.js" ng:autotest></script>
|
||||||
<script type="text/javascript" src="i18n-e2e.js"></script>
|
<script type="text/javascript" src="i18n-e2e.js"></script>
|
||||||
|
|
|
||||||
7483
images/docs/guide/concepts.graffle/data.plist
Normal file
BIN
images/docs/guide/concepts.graffle/image1.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
images/docs/guide/concepts.graffle/image4.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
images/docs/guide/concepts.graffle/image5.png
Normal file
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -80,7 +80,10 @@ StaticServlet.MimeMap = {
|
||||||
'jpeg': 'image/jpeg',
|
'jpeg': 'image/jpeg',
|
||||||
'gif': 'image/gif',
|
'gif': 'image/gif',
|
||||||
'png': 'image/png',
|
'png': 'image/png',
|
||||||
'manifest': 'text/cache-manifest'
|
'manifest': 'text/cache-manifest',
|
||||||
|
// it should be application/font-woff
|
||||||
|
// but only this silences chrome warnings
|
||||||
|
'woff': 'font/opentype'
|
||||||
};
|
};
|
||||||
|
|
||||||
StaticServlet.prototype.handleRequest = function(req, res) {
|
StaticServlet.prototype.handleRequest = function(req, res) {
|
||||||
|
|
@ -105,6 +108,7 @@ StaticServlet.prototype.handleRequest = function(req, res) {
|
||||||
path = path.replace(match[0], '/index.html');
|
path = path.replace(match[0], '/index.html');
|
||||||
sys.puts('Rewrite to ' + path);
|
sys.puts('Rewrite to ' + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// end of docs rewriting
|
// end of docs rewriting
|
||||||
|
|
||||||
fs.stat(path, function(err, stat) {
|
fs.stat(path, function(err, stat) {
|
||||||
|
|
|
||||||
|
|
@ -165,7 +165,7 @@ function JQLite(element) {
|
||||||
var div = document.createElement('div');
|
var div = document.createElement('div');
|
||||||
// Read about the NoScope elements here:
|
// Read about the NoScope elements here:
|
||||||
// http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
|
// http://msdn.microsoft.com/en-us/library/ms533897(VS.85).aspx
|
||||||
div.innerHTML = '<div> </div>' + element; // IE insanity to make NoScope elements work!
|
div.innerHTML = '<div> </div>' + element; // IE insanity to make NoScope elements work!
|
||||||
div.removeChild(div.firstChild); // remove the superfluous div
|
div.removeChild(div.firstChild); // remove the superfluous div
|
||||||
JQLiteAddNodes(this, div.childNodes);
|
JQLiteAddNodes(this, div.childNodes);
|
||||||
this.remove(); // detach the elements from the temporary DOM div.
|
this.remove(); // detach the elements from the temporary DOM div.
|
||||||
|
|
|
||||||
|
|
@ -193,7 +193,7 @@ function setupModuleLoader(window) {
|
||||||
* @param {Function} directiveFactory Factory function for creating new instance of
|
* @param {Function} directiveFactory Factory function for creating new instance of
|
||||||
* directives.
|
* directives.
|
||||||
* @description
|
* @description
|
||||||
* See {@link ng.$compileProvider.directive $compileProvider.directive()}.
|
* See {@link ng.$compileProvider#directive $compileProvider.directive()}.
|
||||||
*/
|
*/
|
||||||
directive: invokeLater('$compileProvider', 'directive'),
|
directive: invokeLater('$compileProvider', 'directive'),
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@ var NON_ASSIGNABLE_MODEL_EXPRESSION = 'Non-assignable model expression: ';
|
||||||
* can then be used to link {@link ng.$rootScope.Scope scope} and the template together.
|
* can then be used to link {@link ng.$rootScope.Scope scope} and the template together.
|
||||||
*
|
*
|
||||||
* The compilation is a process of walking the DOM tree and trying to match DOM elements to
|
* The compilation is a process of walking the DOM tree and trying to match DOM elements to
|
||||||
* {@link ng.$compileProvider.directive directives}. For each match it
|
* {@link ng.$compileProvider#directive directives}. For each match it
|
||||||
* executes corresponding template function and collects the
|
* executes corresponding template function and collects the
|
||||||
* instance functions into a single template function which is then returned.
|
* instance functions into a single template function which is then returned.
|
||||||
*
|
*
|
||||||
|
|
@ -149,20 +149,6 @@ var NON_ASSIGNABLE_MODEL_EXPRESSION = 'Non-assignable model expression: ';
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @ngdoc function
|
|
||||||
* @name ng.$compileProvider#directive
|
|
||||||
* @methodOf ng.$compileProvider
|
|
||||||
* @function
|
|
||||||
*
|
|
||||||
* @description
|
|
||||||
* Register a new directive with compiler
|
|
||||||
*
|
|
||||||
* @param {string} name name of the directive.
|
|
||||||
* @param {function} directiveFactory An injectable directive factory function.
|
|
||||||
* @returns {ng.$compileProvider} Self for chaining.
|
|
||||||
*/
|
|
||||||
$CompileProvider.$inject = ['$provide'];
|
$CompileProvider.$inject = ['$provide'];
|
||||||
function $CompileProvider($provide) {
|
function $CompileProvider($provide) {
|
||||||
var hasDirectives = {},
|
var hasDirectives = {},
|
||||||
|
|
@ -174,17 +160,18 @@ function $CompileProvider($provide) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc function
|
* @ngdoc function
|
||||||
* @name ng.$compileProvider.directive
|
* @name ng.$compileProvider#directive
|
||||||
* @methodOf ng.$compileProvider
|
* @methodOf ng.$compileProvider
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
* Register directives with the compiler.
|
* Register a new directives with the compiler.
|
||||||
*
|
*
|
||||||
* @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
|
* @param {string} name Name of the directive in camel-case. (ie <code>ngBind</code> which will match as
|
||||||
* <code>ng-bind</code>).
|
* <code>ng-bind</code>).
|
||||||
* @param {function} directiveFactory An injectable directive factroy function. See {@link guide/directive} for more
|
* @param {function} directiveFactory An injectable directive factroy function. See {@link guide/directive} for more
|
||||||
* info.
|
* info.
|
||||||
|
* @returns {ng.$compileProvider} Self for chaining.
|
||||||
*/
|
*/
|
||||||
this.directive = function registerDirective(name, directiveFactory) {
|
this.directive = function registerDirective(name, directiveFactory) {
|
||||||
if (isString(name)) {
|
if (isString(name)) {
|
||||||
|
|
@ -310,6 +297,15 @@ function $CompileProvider($provide) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var startSymbol = $interpolate.startSymbol(),
|
||||||
|
endSymbol = $interpolate.endSymbol(),
|
||||||
|
denormalizeTemplate = (startSymbol == '{{' || endSymbol == '}}')
|
||||||
|
? identity
|
||||||
|
: function denormalizeTemplate(template) {
|
||||||
|
return template.replace(/\{\{/g, startSymbol).replace(/}}/g, endSymbol);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return compile;
|
return compile;
|
||||||
|
|
||||||
//================================
|
//================================
|
||||||
|
|
@ -323,7 +319,7 @@ function $CompileProvider($provide) {
|
||||||
// not be able to attach scope data to them, so we will wrap them in <span>
|
// not be able to attach scope data to them, so we will wrap them in <span>
|
||||||
forEach($compileNode, function(node, index){
|
forEach($compileNode, function(node, index){
|
||||||
if (node.nodeType == 3 /* text node */) {
|
if (node.nodeType == 3 /* text node */) {
|
||||||
$compileNode[index] = jqLite(node).wrap('<span>').parent()[0];
|
$compileNode[index] = jqLite(node).wrap('<span></span>').parent()[0];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var compositeLinkFn = compileNodes($compileNode, transcludeFn, $compileNode, maxPriority);
|
var compositeLinkFn = compileNodes($compileNode, transcludeFn, $compileNode, maxPriority);
|
||||||
|
|
@ -589,14 +585,17 @@ function $CompileProvider($provide) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (directiveValue = directive.template) {
|
if ((directiveValue = directive.template)) {
|
||||||
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
assertNoDuplicate('template', templateDirective, directive, $compileNode);
|
||||||
templateDirective = directive;
|
templateDirective = directive;
|
||||||
|
directiveValue = denormalizeTemplate(directiveValue);
|
||||||
$template = jqLite('<div>' + trim(directiveValue) + '</div>').contents();
|
|
||||||
compileNode = $template[0];
|
|
||||||
|
|
||||||
if (directive.replace) {
|
if (directive.replace) {
|
||||||
|
$template = jqLite('<div>' +
|
||||||
|
trim(directiveValue) +
|
||||||
|
'</div>').contents();
|
||||||
|
compileNode = $template[0];
|
||||||
|
|
||||||
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
if ($template.length != 1 || compileNode.nodeType !== 1) {
|
||||||
throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
|
throw new Error(MULTI_ROOT_TEMPLATE_ERROR + directiveValue);
|
||||||
}
|
}
|
||||||
|
|
@ -909,6 +908,8 @@ function $CompileProvider($provide) {
|
||||||
success(function(content) {
|
success(function(content) {
|
||||||
var compileNode, tempTemplateAttrs, $template;
|
var compileNode, tempTemplateAttrs, $template;
|
||||||
|
|
||||||
|
content = denormalizeTemplate(content);
|
||||||
|
|
||||||
if (replace) {
|
if (replace) {
|
||||||
$template = jqLite('<div>' + trim(content) + '</div>').contents();
|
$template = jqLite('<div>' + trim(content) + '</div>').contents();
|
||||||
compileNode = $template[0];
|
compileNode = $template[0];
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* @ngdoc directive
|
||||||
|
* @name ng.directive:a
|
||||||
|
* @restrict E
|
||||||
|
*
|
||||||
|
* @description
|
||||||
* Modifies the default behavior of html A tag, so that the default action is prevented when href
|
* Modifies the default behavior of html A tag, so that the default action is prevented when href
|
||||||
* attribute is empty.
|
* attribute is empty.
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -227,38 +227,62 @@ function FormController(element, attrs) {
|
||||||
</doc:scenario>
|
</doc:scenario>
|
||||||
</doc:example>
|
</doc:example>
|
||||||
*/
|
*/
|
||||||
var formDirectiveDir = {
|
var formDirectiveFactory = function(isNgForm) {
|
||||||
name: 'form',
|
return ['$timeout', function($timeout) {
|
||||||
restrict: 'E',
|
var formDirective = {
|
||||||
controller: FormController,
|
name: 'form',
|
||||||
compile: function() {
|
restrict: 'E',
|
||||||
return {
|
controller: FormController,
|
||||||
pre: function(scope, formElement, attr, controller) {
|
compile: function() {
|
||||||
if (!attr.action) {
|
return {
|
||||||
formElement.bind('submit', function(event) {
|
pre: function(scope, formElement, attr, controller) {
|
||||||
event.preventDefault();
|
if (!attr.action) {
|
||||||
});
|
// we can't use jq events because if a form is destroyed during submission the default
|
||||||
}
|
// action is not prevented. see #1238
|
||||||
|
//
|
||||||
|
// IE 9 is not affected because it doesn't fire a submit event and try to do a full
|
||||||
|
// page reload if the form was destroyed by submission of the form via a click handler
|
||||||
|
// on a button in the form. Looks like an IE9 specific bug.
|
||||||
|
var preventDefaultListener = function(event) {
|
||||||
|
event.preventDefault
|
||||||
|
? event.preventDefault()
|
||||||
|
: event.returnValue = false; // IE
|
||||||
|
};
|
||||||
|
|
||||||
var parentFormCtrl = formElement.parent().controller('form'),
|
addEventListenerFn(formElement[0], 'submit', preventDefaultListener);
|
||||||
alias = attr.name || attr.ngForm;
|
|
||||||
|
|
||||||
if (alias) {
|
// unregister the preventDefault listener so that we don't not leak memory but in a
|
||||||
scope[alias] = controller;
|
// way that will achieve the prevention of the default action.
|
||||||
}
|
formElement.bind('$destroy', function() {
|
||||||
if (parentFormCtrl) {
|
$timeout(function() {
|
||||||
formElement.bind('$destroy', function() {
|
removeEventListenerFn(formElement[0], 'submit', preventDefaultListener);
|
||||||
parentFormCtrl.$removeControl(controller);
|
}, 0, false);
|
||||||
if (alias) {
|
});
|
||||||
scope[alias] = undefined;
|
|
||||||
}
|
}
|
||||||
extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
|
|
||||||
});
|
var parentFormCtrl = formElement.parent().controller('form'),
|
||||||
}
|
alias = attr.name || attr.ngForm;
|
||||||
|
|
||||||
|
if (alias) {
|
||||||
|
scope[alias] = controller;
|
||||||
|
}
|
||||||
|
if (parentFormCtrl) {
|
||||||
|
formElement.bind('$destroy', function() {
|
||||||
|
parentFormCtrl.$removeControl(controller);
|
||||||
|
if (alias) {
|
||||||
|
scope[alias] = undefined;
|
||||||
|
}
|
||||||
|
extend(controller, nullFormCtrl); //stop propagating child destruction handlers upwards
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
|
||||||
|
return isNgForm ? extend(copy(formDirective), {restrict: 'EAC'}) : formDirective;
|
||||||
|
}];
|
||||||
};
|
};
|
||||||
|
|
||||||
var formDirective = valueFn(formDirectiveDir);
|
var formDirective = formDirectiveFactory();
|
||||||
var ngFormDirective = valueFn(extend(copy(formDirectiveDir), {restrict: 'EAC'}));
|
var ngFormDirective = formDirectiveFactory(true);
|
||||||
|
|
|
||||||
|
|
@ -1219,7 +1219,7 @@ var ngListDirective = function() {
|
||||||
|
|
||||||
ctrl.$parsers.push(parse);
|
ctrl.$parsers.push(parse);
|
||||||
ctrl.$formatters.push(function(value) {
|
ctrl.$formatters.push(function(value) {
|
||||||
if (isArray(value) && !equals(parse(ctrl.$viewValue), value)) {
|
if (isArray(value)) {
|
||||||
return value.join(', ');
|
return value.join(', ');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -178,11 +178,14 @@ var ngPluralizeDirective = ['$locale', '$interpolate', function($locale, $interp
|
||||||
whenExp = element.attr(attr.$attr.when), // this is because we have {{}} in attrs
|
whenExp = element.attr(attr.$attr.when), // this is because we have {{}} in attrs
|
||||||
offset = attr.offset || 0,
|
offset = attr.offset || 0,
|
||||||
whens = scope.$eval(whenExp),
|
whens = scope.$eval(whenExp),
|
||||||
whensExpFns = {};
|
whensExpFns = {},
|
||||||
|
startSymbol = $interpolate.startSymbol(),
|
||||||
|
endSymbol = $interpolate.endSymbol();
|
||||||
|
|
||||||
forEach(whens, function(expression, key) {
|
forEach(whens, function(expression, key) {
|
||||||
whensExpFns[key] =
|
whensExpFns[key] =
|
||||||
$interpolate(expression.replace(BRACE, '{{' + numberExp + '-' + offset + '}}'));
|
$interpolate(expression.replace(BRACE, startSymbol + numberExp + '-' +
|
||||||
|
offset + endSymbol));
|
||||||
});
|
});
|
||||||
|
|
||||||
scope.$watch(function() {
|
scope.$watch(function() {
|
||||||
|
|
|
||||||
|
|
@ -521,7 +521,6 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
priority: 100,
|
priority: 100,
|
||||||
require: '^select',
|
|
||||||
compile: function(element, attr) {
|
compile: function(element, attr) {
|
||||||
if (isUndefined(attr.value)) {
|
if (isUndefined(attr.value)) {
|
||||||
var interpolateFn = $interpolate(element.text(), true);
|
var interpolateFn = $interpolate(element.text(), true);
|
||||||
|
|
@ -530,8 +529,13 @@ var optionDirective = ['$interpolate', function($interpolate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return function (scope, element, attr, selectCtrl) {
|
return function (scope, element, attr) {
|
||||||
if (selectCtrl.databound) {
|
var selectCtrlName = '$selectController',
|
||||||
|
parent = element.parent(),
|
||||||
|
selectCtrl = parent.data(selectCtrlName) ||
|
||||||
|
parent.parent().data(selectCtrlName); // in case we are in optgroup
|
||||||
|
|
||||||
|
if (selectCtrl && selectCtrl.databound) {
|
||||||
// For some reason Opera defaults to true and if not overridden this messes up the repeater.
|
// For some reason Opera defaults to true and if not overridden this messes up the repeater.
|
||||||
// We don't want the view to drive the initialization of the model anyway.
|
// We don't want the view to drive the initialization of the model anyway.
|
||||||
element.prop('selected', false);
|
element.prop('selected', false);
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @ngdoc function
|
* @ngdoc object
|
||||||
* @name ng.$interpolateProvider
|
* @name ng.$interpolateProvider
|
||||||
* @function
|
* @function
|
||||||
*
|
*
|
||||||
* @description
|
* @description
|
||||||
*
|
*
|
||||||
* Used for configuring the interpolation markup. Deafults to `{{` and `}}`.
|
* Used for configuring the interpolation markup. Defaults to `{{` and `}}`.
|
||||||
*/
|
*/
|
||||||
function $InterpolateProvider() {
|
function $InterpolateProvider() {
|
||||||
var startSymbol = '{{';
|
var startSymbol = '{{';
|
||||||
|
|
@ -20,7 +20,8 @@ function $InterpolateProvider() {
|
||||||
* @description
|
* @description
|
||||||
* Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
|
* Symbol to denote start of expression in the interpolated string. Defaults to `{{`.
|
||||||
*
|
*
|
||||||
* @prop {string=} value new value to set the starting symbol to.
|
* @param {string=} value new value to set the starting symbol to.
|
||||||
|
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
|
||||||
*/
|
*/
|
||||||
this.startSymbol = function(value){
|
this.startSymbol = function(value){
|
||||||
if (value) {
|
if (value) {
|
||||||
|
|
@ -38,14 +39,15 @@ function $InterpolateProvider() {
|
||||||
* @description
|
* @description
|
||||||
* Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
|
* Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
|
||||||
*
|
*
|
||||||
* @prop {string=} value new value to set the ending symbol to.
|
* @param {string=} value new value to set the ending symbol to.
|
||||||
|
* @returns {string|self} Returns the symbol when used as getter and self if used as setter.
|
||||||
*/
|
*/
|
||||||
this.endSymbol = function(value){
|
this.endSymbol = function(value){
|
||||||
if (value) {
|
if (value) {
|
||||||
endSymbol = value;
|
endSymbol = value;
|
||||||
return this;
|
return this;
|
||||||
} else {
|
} else {
|
||||||
return startSymbol;
|
return endSymbol;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -87,7 +89,7 @@ function $InterpolateProvider() {
|
||||||
* against.
|
* against.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
return function(text, mustHaveExpression) {
|
function $interpolate(text, mustHaveExpression) {
|
||||||
var startIndex,
|
var startIndex,
|
||||||
endIndex,
|
endIndex,
|
||||||
index = 0,
|
index = 0,
|
||||||
|
|
@ -139,7 +141,43 @@ function $InterpolateProvider() {
|
||||||
fn.parts = parts;
|
fn.parts = parts;
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name ng.$interpolate#startSymbol
|
||||||
|
* @methodOf ng.$interpolate
|
||||||
|
* @description
|
||||||
|
* Symbol to denote the start of expression in the interpolated string. Defaults to `{{`.
|
||||||
|
*
|
||||||
|
* Use {@link ng.$interpolateProvider#startSymbol $interpolateProvider#startSymbol} to change
|
||||||
|
* the symbol.
|
||||||
|
*
|
||||||
|
* @returns {string} start symbol.
|
||||||
|
*/
|
||||||
|
$interpolate.startSymbol = function() {
|
||||||
|
return startSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @ngdoc method
|
||||||
|
* @name ng.$interpolate#endSymbol
|
||||||
|
* @methodOf ng.$interpolate
|
||||||
|
* @description
|
||||||
|
* Symbol to denote the end of expression in the interpolated string. Defaults to `}}`.
|
||||||
|
*
|
||||||
|
* Use {@link ng.$interpolateProvider#endSymbol $interpolateProvider#endSymbol} to change
|
||||||
|
* the symbol.
|
||||||
|
*
|
||||||
|
* @returns {string} start symbol.
|
||||||
|
*/
|
||||||
|
$interpolate.endSymbol = function() {
|
||||||
|
return endSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $interpolate;
|
||||||
}];
|
}];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,27 +12,25 @@
|
||||||
* The main purpose of this service is to simplify debugging and troubleshooting.
|
* The main purpose of this service is to simplify debugging and troubleshooting.
|
||||||
*
|
*
|
||||||
* @example
|
* @example
|
||||||
<doc:example>
|
<example>
|
||||||
<doc:source>
|
<file name="script.js">
|
||||||
<script>
|
function LogCtrl($scope, $log) {
|
||||||
function LogCtrl($log) {
|
$scope.$log = $log;
|
||||||
this.$log = $log;
|
$scope.message = 'Hello World!';
|
||||||
this.message = 'Hello World!';
|
}
|
||||||
}
|
</file>
|
||||||
</script>
|
<file name="index.html">
|
||||||
<div ng-controller="LogCtrl">
|
<div ng-controller="LogCtrl">
|
||||||
<p>Reload this page with open console, enter text and hit the log button...</p>
|
<p>Reload this page with open console, enter text and hit the log button...</p>
|
||||||
Message:
|
Message:
|
||||||
<input type="text" ng-model="message"/>
|
<input type="text" ng-model="message"/>
|
||||||
<button ng-click="$log.log(message)">log</button>
|
<button ng-click="$log.log(message)">log</button>
|
||||||
<button ng-click="$log.warn(message)">warn</button>
|
<button ng-click="$log.warn(message)">warn</button>
|
||||||
<button ng-click="$log.info(message)">info</button>
|
<button ng-click="$log.info(message)">info</button>
|
||||||
<button ng-click="$log.error(message)">error</button>
|
<button ng-click="$log.error(message)">error</button>
|
||||||
</div>
|
</div>
|
||||||
</doc:source>
|
</file>
|
||||||
<doc:scenario>
|
</example>
|
||||||
</doc:scenario>
|
|
||||||
</doc:example>
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function $LogProvider(){
|
function $LogProvider(){
|
||||||
|
|
|
||||||
|
|
@ -326,9 +326,9 @@ function $RootScopeProvider(){
|
||||||
*
|
*
|
||||||
* Usually you don't call `$digest()` directly in
|
* Usually you don't call `$digest()` directly in
|
||||||
* {@link ng.directive:ngController controllers} or in
|
* {@link ng.directive:ngController controllers} or in
|
||||||
* {@link ng.$compileProvider.directive directives}.
|
* {@link ng.$compileProvider#directive directives}.
|
||||||
* Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
|
* Instead a call to {@link ng.$rootScope.Scope#$apply $apply()} (typically from within a
|
||||||
* {@link ng.$compileProvider.directive directives}) will force a `$digest()`.
|
* {@link ng.$compileProvider#directive directives}) will force a `$digest()`.
|
||||||
*
|
*
|
||||||
* If you want to be notified whenever `$digest()` is called,
|
* If you want to be notified whenever `$digest()` is called,
|
||||||
* you can register a `watchExpression` function with {@link ng.$rootScope.Scope#$watch $watch()}
|
* you can register a `watchExpression` function with {@link ng.$rootScope.Scope#$watch $watch()}
|
||||||
|
|
@ -614,8 +614,8 @@ function $RootScopeProvider(){
|
||||||
* @param {function(event)} listener Function to call when the event is emitted.
|
* @param {function(event)} listener Function to call when the event is emitted.
|
||||||
* @returns {function()} Returns a deregistration function for this listener.
|
* @returns {function()} Returns a deregistration function for this listener.
|
||||||
*
|
*
|
||||||
* The event listener function format is: `function(event)`. The `event` object passed into the
|
* The event listener function format is: `function(event, args...)`. The `event` object
|
||||||
* listener has the following attributes
|
* passed into the listener has the following attributes:
|
||||||
*
|
*
|
||||||
* - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
|
* - `targetScope` - {Scope}: the scope on which the event was `$emit`-ed or `$broadcast`-ed.
|
||||||
* - `currentScope` - {Scope}: the current scope which is handling the event.
|
* - `currentScope` - {Scope}: the current scope which is handling the event.
|
||||||
|
|
|
||||||
|
|
@ -27,8 +27,9 @@ function $RouteProvider(){
|
||||||
*
|
*
|
||||||
* Object properties:
|
* Object properties:
|
||||||
*
|
*
|
||||||
* - `controller` – `{function()=}` – Controller fn that should be associated with newly
|
* - `controller` – `{(string|function()=}` – Controller fn that should be associated with newly
|
||||||
* created scope.
|
* created scope or the name of a {@link angular.Module#controller registered controller}
|
||||||
|
* if passed as a string.
|
||||||
* - `template` – `{string=}` – html template as a string that should be used by
|
* - `template` – `{string=}` – html template as a string that should be used by
|
||||||
* {@link ng.directive:ngView ngView} or
|
* {@link ng.directive:ngView ngView} or
|
||||||
* {@link ng.directive:ngInclude ngInclude} directives.
|
* {@link ng.directive:ngInclude ngInclude} directives.
|
||||||
|
|
@ -38,7 +39,7 @@ function $RouteProvider(){
|
||||||
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
* - `resolve` - `{Object.<string, function>=}` - An optional map of dependencies which should
|
||||||
* be injected into the controller. If any of these dependencies are promises, they will be
|
* be injected into the controller. If any of these dependencies are promises, they will be
|
||||||
* resolved and converted to a value before the controller is instantiated and the
|
* resolved and converted to a value before the controller is instantiated and the
|
||||||
* `$aftreRouteChange` event is fired. The map object is:
|
* `$afterRouteChange` event is fired. The map object is:
|
||||||
*
|
*
|
||||||
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
* - `key` – `{string}`: a name of a dependency to be injected into the controller.
|
||||||
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
* - `factory` - `{string|function}`: If `string` then it is an alias for a service.
|
||||||
|
|
|
||||||
28
src/ngMock/angular-mocks.js
vendored
|
|
@ -1591,9 +1591,29 @@ window.jasmine && (function(window) {
|
||||||
|
|
||||||
afterEach(function() {
|
afterEach(function() {
|
||||||
var spec = getCurrentSpec();
|
var spec = getCurrentSpec();
|
||||||
|
var injector = spec.$injector;
|
||||||
|
|
||||||
spec.$injector = null;
|
spec.$injector = null;
|
||||||
spec.$modules = null;
|
spec.$modules = null;
|
||||||
|
|
||||||
|
if (injector) {
|
||||||
|
injector.get('$rootElement').unbind();
|
||||||
|
injector.get('$browser').pollFns.length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
angular.mock.clearDataCache();
|
angular.mock.clearDataCache();
|
||||||
|
|
||||||
|
// clean up jquery's fragment cache
|
||||||
|
angular.forEach(angular.element.fragments, function(val, key) {
|
||||||
|
delete angular.element.fragments[key];
|
||||||
|
});
|
||||||
|
|
||||||
|
MockXhr.$$lastInstance = null;
|
||||||
|
|
||||||
|
angular.forEach(angular.callbacks, function(val, key) {
|
||||||
|
delete angular.callbacks[key];
|
||||||
|
});
|
||||||
|
angular.callbacks.counter = 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
function getCurrentSpec() {
|
function getCurrentSpec() {
|
||||||
|
|
@ -1694,7 +1714,7 @@ window.jasmine && (function(window) {
|
||||||
*/
|
*/
|
||||||
window.inject = angular.mock.inject = function() {
|
window.inject = angular.mock.inject = function() {
|
||||||
var blockFns = Array.prototype.slice.call(arguments, 0);
|
var blockFns = Array.prototype.slice.call(arguments, 0);
|
||||||
var stack = new Error('Declaration Location').stack;
|
var errorForStack = new Error('Declaration Location');
|
||||||
return isSpecRunning() ? workFn() : workFn;
|
return isSpecRunning() ? workFn() : workFn;
|
||||||
/////////////////////
|
/////////////////////
|
||||||
function workFn() {
|
function workFn() {
|
||||||
|
|
@ -1710,10 +1730,12 @@ window.jasmine && (function(window) {
|
||||||
try {
|
try {
|
||||||
injector.invoke(blockFns[i] || angular.noop, this);
|
injector.invoke(blockFns[i] || angular.noop, this);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if(e.stack) e.stack += '\n' + stack;
|
if(e.stack) e.stack += '\n' + errorForStack.stack;
|
||||||
throw e;
|
throw e;
|
||||||
|
} finally {
|
||||||
|
errorForStack = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
})(window);
|
})(window);
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,9 @@
|
||||||
* @param {string} text Input text.
|
* @param {string} text Input text.
|
||||||
* @returns {string} Html-linkified text.
|
* @returns {string} Html-linkified text.
|
||||||
*
|
*
|
||||||
|
* @usage
|
||||||
|
<span ng-bind-html="linky_expression | linky"></span>
|
||||||
|
*
|
||||||
* @example
|
* @example
|
||||||
<doc:example module="ngSanitize">
|
<doc:example module="ngSanitize">
|
||||||
<doc:source>
|
<doc:source>
|
||||||
|
|
|
||||||
|
|
@ -322,7 +322,7 @@ describe('angular', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('angularInit', function() {
|
describe('angularInit', function() {
|
||||||
var bootstrap;
|
var bootstrapSpy;
|
||||||
var element;
|
var element;
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
|
|
@ -331,73 +331,93 @@ describe('angular', function() {
|
||||||
return element.getElementById[id] || [];
|
return element.getElementById[id] || [];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
querySelectorAll: function(arg) {
|
||||||
|
return element.querySelectorAll[arg] || [];
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
getAttribute: function(name) {
|
getAttribute: function(name) {
|
||||||
return element[name];
|
return element[name];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
bootstrap = jasmine.createSpy('bootstrap');
|
bootstrapSpy = jasmine.createSpy('bootstrapSpy');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should do nothing when not found', function() {
|
it('should do nothing when not found', function() {
|
||||||
angularInit(element, bootstrap);
|
angularInit(element, bootstrapSpy);
|
||||||
expect(bootstrap).not.toHaveBeenCalled();
|
expect(bootstrapSpy).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should look for ngApp directive as attr', function() {
|
||||||
|
var appElement = jqLite('<div ng-app="ABC"></div>')[0];
|
||||||
|
element.querySelectorAll['[ng-app]'] = [appElement];
|
||||||
|
angularInit(element, bootstrapSpy);
|
||||||
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should look for ngApp directive in id', function() {
|
it('should look for ngApp directive in id', function() {
|
||||||
var appElement = jqLite('<div id="ng-app" data-ng-app="ABC"></div>')[0];
|
var appElement = jqLite('<div id="ng-app" data-ng-app="ABC"></div>')[0];
|
||||||
jqLite(document.body).append(appElement);
|
jqLite(document.body).append(appElement);
|
||||||
angularInit(element, bootstrap);
|
angularInit(element, bootstrapSpy);
|
||||||
expect(bootstrap).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should look for ngApp directive in className', function() {
|
it('should look for ngApp directive in className', function() {
|
||||||
var appElement = jqLite('<div data-ng-app="ABC"></div>')[0];
|
var appElement = jqLite('<div data-ng-app="ABC"></div>')[0];
|
||||||
element.querySelectorAll = function(arg) { return element.querySelectorAll[arg] || []; }
|
|
||||||
element.querySelectorAll['.ng\\:app'] = [appElement];
|
element.querySelectorAll['.ng\\:app'] = [appElement];
|
||||||
angularInit(element, bootstrap);
|
angularInit(element, bootstrapSpy);
|
||||||
expect(bootstrap).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should look for ngApp directive using querySelectorAll', function() {
|
it('should look for ngApp directive using querySelectorAll', function() {
|
||||||
var appElement = jqLite('<div x-ng-app="ABC"></div>')[0];
|
var appElement = jqLite('<div x-ng-app="ABC"></div>')[0];
|
||||||
element.querySelectorAll = function(arg) { return element.querySelectorAll[arg] || []; }
|
|
||||||
element.querySelectorAll['[ng\\:app]'] = [ appElement ];
|
element.querySelectorAll['[ng\\:app]'] = [ appElement ];
|
||||||
angularInit(element, bootstrap);
|
angularInit(element, bootstrapSpy);
|
||||||
expect(bootstrap).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should bootstrap using class name', function() {
|
it('should bootstrap using class name', function() {
|
||||||
var appElement = jqLite('<div class="ng-app: ABC;"></div>')[0];
|
var appElement = jqLite('<div class="ng-app: ABC;"></div>')[0];
|
||||||
angularInit(jqLite('<div></div>').append(appElement)[0], bootstrap);
|
angularInit(jqLite('<div></div>').append(appElement)[0], bootstrapSpy);
|
||||||
expect(bootstrap).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, ['ABC']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should bootstrap anonymously', function() {
|
it('should bootstrap anonymously', function() {
|
||||||
var appElement = jqLite('<div x-ng-app></div>')[0];
|
var appElement = jqLite('<div x-ng-app></div>')[0];
|
||||||
element.querySelectorAll = function(arg) { return element.querySelectorAll[arg] || []; }
|
|
||||||
element.querySelectorAll['[x-ng-app]'] = [ appElement ];
|
element.querySelectorAll['[x-ng-app]'] = [ appElement ];
|
||||||
angularInit(element, bootstrap);
|
angularInit(element, bootstrapSpy);
|
||||||
expect(bootstrap).toHaveBeenCalledOnceWith(appElement, []);
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should bootstrap anonymously using class only', function() {
|
it('should bootstrap anonymously using class only', function() {
|
||||||
var appElement = jqLite('<div class="ng-app"></div>')[0];
|
var appElement = jqLite('<div class="ng-app"></div>')[0];
|
||||||
angularInit(jqLite('<div></div>').append(appElement)[0], bootstrap);
|
angularInit(jqLite('<div></div>').append(appElement)[0], bootstrapSpy);
|
||||||
expect(bootstrap).toHaveBeenCalledOnceWith(appElement, []);
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, []);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should bootstrap if the annotation is on the root element', function() {
|
it('should bootstrap if the annotation is on the root element', function() {
|
||||||
var appElement = jqLite('<div class="ng-app"></div>')[0];
|
var appElement = jqLite('<div class="ng-app"></div>')[0];
|
||||||
angularInit(appElement, bootstrap);
|
angularInit(appElement, bootstrapSpy);
|
||||||
expect(bootstrap).toHaveBeenCalledOnceWith(appElement, []);
|
expect(bootstrapSpy).toHaveBeenCalledOnceWith(appElement, []);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should complain if app module cannot be found', function() {
|
||||||
|
var appElement = jqLite('<div ng-app="doesntexist"></div>')[0];
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
angularInit(appElement, bootstrap);
|
||||||
|
}).toThrow('No module: doesntexist');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -535,6 +555,17 @@ describe('angular', function() {
|
||||||
expect(element.data('$injector')).toBe(injector);
|
expect(element.data('$injector')).toBe(injector);
|
||||||
dealoc(element);
|
dealoc(element);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should complain if app module can't be found", function() {
|
||||||
|
var element = jqLite('<div>{{1+2}}</div>');
|
||||||
|
|
||||||
|
expect(function() {
|
||||||
|
angular.bootstrap(element, ['doesntexist']);
|
||||||
|
}).toThrow('No module: doesntexist');
|
||||||
|
|
||||||
|
expect(element.html()).toBe('{{1+2}}');
|
||||||
|
dealoc(element);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,9 @@
|
||||||
describe('jqLite', function() {
|
describe('jqLite', function() {
|
||||||
var scope, a, b, c;
|
var scope, a, b, c;
|
||||||
|
|
||||||
|
|
||||||
|
beforeEach(module(provideLog));
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function() {
|
||||||
a = jqLite('<div>A</div>')[0];
|
a = jqLite('<div>A</div>')[0];
|
||||||
b = jqLite('<div>B</div>')[0];
|
b = jqLite('<div>B</div>')[0];
|
||||||
|
|
@ -241,7 +244,7 @@ describe('jqLite', function() {
|
||||||
expect(jqLite(c).data('prop')).toBeUndefined();
|
expect(jqLite(c).data('prop')).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call $destroy function if element removed', function() {
|
it('should emit $destroy event if element removed via remove()', function() {
|
||||||
var log = '';
|
var log = '';
|
||||||
var element = jqLite(a);
|
var element = jqLite(a);
|
||||||
element.bind('$destroy', function() {log+= 'destroy;';});
|
element.bind('$destroy', function() {log+= 'destroy;';});
|
||||||
|
|
@ -249,6 +252,18 @@ describe('jqLite', function() {
|
||||||
expect(log).toEqual('destroy;');
|
expect(log).toEqual('destroy;');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should emit $destroy event if an element is removed via html()', inject(function(log) {
|
||||||
|
var element = jqLite('<div><span>x</span></div>');
|
||||||
|
element.find('span').bind('$destroy', log.fn('destroyed'));
|
||||||
|
|
||||||
|
element.html('');
|
||||||
|
|
||||||
|
expect(element.html()).toBe('');
|
||||||
|
expect(log).toEqual('destroyed');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should retrieve all data if called without params', function() {
|
it('should retrieve all data if called without params', function() {
|
||||||
var element = jqLite(a);
|
var element = jqLite(a);
|
||||||
expect(element.data()).toEqual({});
|
expect(element.data()).toEqual({});
|
||||||
|
|
|
||||||
|
|
@ -369,7 +369,6 @@ describe('$compile', function() {
|
||||||
|
|
||||||
describe('template', function() {
|
describe('template', function() {
|
||||||
|
|
||||||
|
|
||||||
beforeEach(module(function() {
|
beforeEach(module(function() {
|
||||||
directive('replace', valueFn({
|
directive('replace', valueFn({
|
||||||
restrict: 'CAM',
|
restrict: 'CAM',
|
||||||
|
|
@ -394,7 +393,7 @@ describe('$compile', function() {
|
||||||
compile: function(element, attr) {
|
compile: function(element, attr) {
|
||||||
attr.$set('compiled', 'COMPILED');
|
attr.$set('compiled', 'COMPILED');
|
||||||
expect(element).toBe(attr.$$element);
|
expect(element).toBe(attr.$$element);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
@ -1373,6 +1372,47 @@ describe('$compile', function() {
|
||||||
'<option>Greet Misko!</option>' +
|
'<option>Greet Misko!</option>' +
|
||||||
'</select>');
|
'</select>');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should support custom start/end interpolation symbols in template and directive template',
|
||||||
|
function() {
|
||||||
|
module(function($interpolateProvider, $compileProvider) {
|
||||||
|
$interpolateProvider.startSymbol('##').endSymbol(']]');
|
||||||
|
$compileProvider.directive('myDirective', function() {
|
||||||
|
return {
|
||||||
|
template: '<span>{{hello}}|{{hello|uppercase}}</span>'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
inject(function($compile, $rootScope) {
|
||||||
|
element = $compile('<div>##hello|uppercase]]|<div my-directive></div></div>')($rootScope);
|
||||||
|
$rootScope.hello = 'ahoj';
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(element.text()).toBe('AHOJ|ahoj|AHOJ');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should support custom start/end interpolation symbols in async directive template',
|
||||||
|
function() {
|
||||||
|
module(function($interpolateProvider, $compileProvider) {
|
||||||
|
$interpolateProvider.startSymbol('##').endSymbol(']]');
|
||||||
|
$compileProvider.directive('myDirective', function() {
|
||||||
|
return {
|
||||||
|
templateUrl: 'myDirective.html'
|
||||||
|
};
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
inject(function($compile, $rootScope, $templateCache) {
|
||||||
|
$templateCache.put('myDirective.html', '<span>{{hello}}|{{hello|uppercase}}</span>');
|
||||||
|
element = $compile('<div>##hello|uppercase]]|<div my-directive></div></div>')($rootScope);
|
||||||
|
$rootScope.hello = 'ahoj';
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(element.text()).toBe('AHOJ|ahoj|AHOJ');
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,36 +64,6 @@ describe('form', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
it('should prevent form submission', function() {
|
|
||||||
var startingUrl = '' + window.location;
|
|
||||||
doc = jqLite('<form name="myForm"><input type="submit" value="submit" />');
|
|
||||||
$compile(doc)(scope);
|
|
||||||
|
|
||||||
browserTrigger(doc.find('input'));
|
|
||||||
waitsFor(
|
|
||||||
function() { return true; },
|
|
||||||
'let browser breath, so that the form submision can manifest itself', 10);
|
|
||||||
|
|
||||||
runs(function() {
|
|
||||||
expect('' + window.location).toEqual(startingUrl);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should not prevent form submission if action attribute present', function() {
|
|
||||||
var callback = jasmine.createSpy('submit').andCallFake(function(event) {
|
|
||||||
expect(event.isDefaultPrevented()).toBe(false);
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
|
|
||||||
doc = $compile('<form name="x" action="some.py" />')(scope);
|
|
||||||
doc.bind('submit', callback);
|
|
||||||
|
|
||||||
browserTrigger(doc, 'submit');
|
|
||||||
expect(callback).toHaveBeenCalledOnce();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
it('should publish form to scope when name attr is defined', function() {
|
it('should publish form to scope when name attr is defined', function() {
|
||||||
doc = $compile('<form name="myForm"></form>')(scope);
|
doc = $compile('<form name="myForm"></form>')(scope);
|
||||||
expect(scope.myForm).toBeTruthy();
|
expect(scope.myForm).toBeTruthy();
|
||||||
|
|
@ -155,6 +125,136 @@ describe('form', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('preventing default submission', function() {
|
||||||
|
|
||||||
|
it('should prevent form submission', function() {
|
||||||
|
var nextTurn = false,
|
||||||
|
submitted = false,
|
||||||
|
reloadPrevented;
|
||||||
|
|
||||||
|
doc = jqLite('<form ng-submit="submitMe()">' +
|
||||||
|
'<input type="submit" value="submit">' +
|
||||||
|
'</form>');
|
||||||
|
|
||||||
|
var assertPreventDefaultListener = function(e) {
|
||||||
|
reloadPrevented = e.defaultPrevented || (e.returnValue === false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// native dom event listeners in IE8 fire in LIFO order so we have to register them
|
||||||
|
// there in different order than in other browsers
|
||||||
|
if (msie==8) addEventListenerFn(doc[0], 'submit', assertPreventDefaultListener);
|
||||||
|
|
||||||
|
$compile(doc)(scope);
|
||||||
|
|
||||||
|
scope.submitMe = function() {
|
||||||
|
submitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msie!=8) addEventListenerFn(doc[0], 'submit', assertPreventDefaultListener);
|
||||||
|
|
||||||
|
browserTrigger(doc.find('input'));
|
||||||
|
|
||||||
|
// let the browser process all events (and potentially reload the page)
|
||||||
|
setTimeout(function() { nextTurn = true;});
|
||||||
|
|
||||||
|
waitsFor(function() { return nextTurn; });
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(reloadPrevented).toBe(true);
|
||||||
|
expect(submitted).toBe(true);
|
||||||
|
|
||||||
|
// prevent mem leak in test
|
||||||
|
removeEventListenerFn(doc[0], 'submit', assertPreventDefaultListener);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should prevent the default when the form is destroyed by a submission via a click event',
|
||||||
|
inject(function($timeout) {
|
||||||
|
doc = jqLite('<div>' +
|
||||||
|
'<form ng-submit="submitMe()">' +
|
||||||
|
'<button ng-click="destroy()"></button>' +
|
||||||
|
'</form>' +
|
||||||
|
'</div>');
|
||||||
|
|
||||||
|
var form = doc.find('form'),
|
||||||
|
destroyed = false,
|
||||||
|
nextTurn = false,
|
||||||
|
submitted = false,
|
||||||
|
reloadPrevented;
|
||||||
|
|
||||||
|
scope.destroy = function() {
|
||||||
|
// yes, I know, scope methods should not do direct DOM manipulation, but I wanted to keep
|
||||||
|
// this test small. Imagine that the destroy action will cause a model change (e.g.
|
||||||
|
// $location change) that will cause some directive to destroy the dom (e.g. ngView+$route)
|
||||||
|
doc.html('');
|
||||||
|
destroyed = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
scope.submitMe = function() {
|
||||||
|
submitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var assertPreventDefaultListener = function(e) {
|
||||||
|
reloadPrevented = e.defaultPrevented || (e.returnValue === false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// native dom event listeners in IE8 fire in LIFO order so we have to register them
|
||||||
|
// there in different order than in other browsers
|
||||||
|
if (msie == 8) addEventListenerFn(form[0], 'submit', assertPreventDefaultListener);
|
||||||
|
|
||||||
|
$compile(doc)(scope);
|
||||||
|
|
||||||
|
if (msie != 8) addEventListenerFn(form[0], 'submit', assertPreventDefaultListener);
|
||||||
|
|
||||||
|
browserTrigger(doc.find('button'), 'click');
|
||||||
|
|
||||||
|
// let the browser process all events (and potentially reload the page)
|
||||||
|
setTimeout(function() { nextTurn = true;}, 100);
|
||||||
|
|
||||||
|
waitsFor(function() { return nextTurn; });
|
||||||
|
|
||||||
|
|
||||||
|
// I can't get IE8 to automatically trigger submit in this test, in production it does it
|
||||||
|
// properly
|
||||||
|
if (msie == 8) browserTrigger(form, 'submit');
|
||||||
|
|
||||||
|
runs(function() {
|
||||||
|
expect(doc.html()).toBe('');
|
||||||
|
expect(destroyed).toBe(true);
|
||||||
|
expect(submitted).toBe(false); // this is known corner-case that is not currently handled
|
||||||
|
// the issue is that the submit listener is destroyed before
|
||||||
|
// the event propagates there. we can fix this if we see
|
||||||
|
// the issue in the wild, I'm not going to bother to do it
|
||||||
|
// now. (i)
|
||||||
|
|
||||||
|
// IE9 is special and it doesn't fire submit event when form was destroyed
|
||||||
|
if (msie != 9) {
|
||||||
|
expect(reloadPrevented).toBe(true);
|
||||||
|
$timeout.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent mem leak in test
|
||||||
|
removeEventListenerFn(form[0], 'submit', assertPreventDefaultListener);
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should NOT prevent form submission if action attribute present', function() {
|
||||||
|
var callback = jasmine.createSpy('submit').andCallFake(function(event) {
|
||||||
|
expect(event.isDefaultPrevented()).toBe(false);
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
doc = $compile('<form action="some.py"></form>')(scope);
|
||||||
|
doc.bind('submit', callback);
|
||||||
|
|
||||||
|
browserTrigger(doc, 'submit');
|
||||||
|
expect(callback).toHaveBeenCalledOnce();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('nested forms', function() {
|
describe('nested forms', function() {
|
||||||
|
|
||||||
it('should chain nested forms', function() {
|
it('should chain nested forms', function() {
|
||||||
|
|
|
||||||
|
|
@ -10,92 +10,92 @@ describe('ngPluralize', function() {
|
||||||
|
|
||||||
|
|
||||||
describe('deal with pluralized strings without offset', function() {
|
describe('deal with pluralized strings without offset', function() {
|
||||||
beforeEach(inject(function($rootScope, $compile) {
|
beforeEach(inject(function($rootScope, $compile) {
|
||||||
element = $compile(
|
element = $compile(
|
||||||
'<ng:pluralize count="email"' +
|
'<ng:pluralize count="email"' +
|
||||||
"when=\"{'0': 'You have no new email'," +
|
"when=\"{'0': 'You have no new email'," +
|
||||||
"'one': 'You have one new email'," +
|
"'one': 'You have one new email'," +
|
||||||
"'other': 'You have {} new emails'}\">" +
|
"'other': 'You have {} new emails'}\">" +
|
||||||
'</ng:pluralize>')($rootScope);
|
'</ng:pluralize>')($rootScope);
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should show single/plural strings', inject(function($rootScope) {
|
it('should show single/plural strings', inject(function($rootScope) {
|
||||||
$rootScope.email = 0;
|
$rootScope.email = 0;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have no new email');
|
expect(element.text()).toBe('You have no new email');
|
||||||
|
|
||||||
$rootScope.email = '0';
|
$rootScope.email = '0';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have no new email');
|
expect(element.text()).toBe('You have no new email');
|
||||||
|
|
||||||
$rootScope.email = 1;
|
$rootScope.email = 1;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have one new email');
|
expect(element.text()).toBe('You have one new email');
|
||||||
|
|
||||||
$rootScope.email = 0.01;
|
$rootScope.email = 0.01;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have 0.01 new emails');
|
expect(element.text()).toBe('You have 0.01 new emails');
|
||||||
|
|
||||||
$rootScope.email = '0.1';
|
$rootScope.email = '0.1';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have 0.1 new emails');
|
expect(element.text()).toBe('You have 0.1 new emails');
|
||||||
|
|
||||||
$rootScope.email = 2;
|
$rootScope.email = 2;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have 2 new emails');
|
expect(element.text()).toBe('You have 2 new emails');
|
||||||
|
|
||||||
$rootScope.email = -0.1;
|
$rootScope.email = -0.1;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have -0.1 new emails');
|
expect(element.text()).toBe('You have -0.1 new emails');
|
||||||
|
|
||||||
$rootScope.email = '-0.01';
|
$rootScope.email = '-0.01';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have -0.01 new emails');
|
expect(element.text()).toBe('You have -0.01 new emails');
|
||||||
|
|
||||||
$rootScope.email = -2;
|
$rootScope.email = -2;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have -2 new emails');
|
expect(element.text()).toBe('You have -2 new emails');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should show single/plural strings with mal-formed inputs', inject(function($rootScope) {
|
it('should show single/plural strings with mal-formed inputs', inject(function($rootScope) {
|
||||||
$rootScope.email = '';
|
$rootScope.email = '';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('');
|
expect(element.text()).toBe('');
|
||||||
|
|
||||||
$rootScope.email = null;
|
$rootScope.email = null;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('');
|
expect(element.text()).toBe('');
|
||||||
|
|
||||||
$rootScope.email = undefined;
|
$rootScope.email = undefined;
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('');
|
expect(element.text()).toBe('');
|
||||||
|
|
||||||
$rootScope.email = 'a3';
|
$rootScope.email = 'a3';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('');
|
expect(element.text()).toBe('');
|
||||||
|
|
||||||
$rootScope.email = '011';
|
$rootScope.email = '011';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have 11 new emails');
|
expect(element.text()).toBe('You have 11 new emails');
|
||||||
|
|
||||||
$rootScope.email = '-011';
|
$rootScope.email = '-011';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have -11 new emails');
|
expect(element.text()).toBe('You have -11 new emails');
|
||||||
|
|
||||||
$rootScope.email = '1fff';
|
$rootScope.email = '1fff';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have one new email');
|
expect(element.text()).toBe('You have one new email');
|
||||||
|
|
||||||
$rootScope.email = '0aa22';
|
$rootScope.email = '0aa22';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have no new email');
|
expect(element.text()).toBe('You have no new email');
|
||||||
|
|
||||||
$rootScope.email = '000001';
|
$rootScope.email = '000001';
|
||||||
$rootScope.$digest();
|
$rootScope.$digest();
|
||||||
expect(element.text()).toBe('You have one new email');
|
expect(element.text()).toBe('You have one new email');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -133,4 +133,41 @@ describe('ngPluralize', function() {
|
||||||
expect(element.text()).toBe('Igor, Misko and 2 other people are viewing.');
|
expect(element.text()).toBe('Igor, Misko and 2 other people are viewing.');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('interpolation', function() {
|
||||||
|
|
||||||
|
it('should support custom interpolation symbols', function() {
|
||||||
|
module(function($interpolateProvider) {
|
||||||
|
$interpolateProvider.startSymbol('[[').endSymbol('%%');
|
||||||
|
});
|
||||||
|
|
||||||
|
inject(function($compile, $rootScope) {
|
||||||
|
element = $compile(
|
||||||
|
"<ng:pluralize count=\"viewCount\" offset=\"1\"" +
|
||||||
|
"when=\"{'0': 'Nobody is viewing.'," +
|
||||||
|
"'1': '[[p1%% is viewing.'," +
|
||||||
|
"'one': '[[p1%% and one other person are viewing.'," +
|
||||||
|
"'other': '[[p1%% and {} other people are viewing.'}\">" +
|
||||||
|
"</ng:pluralize>")($rootScope);
|
||||||
|
$rootScope.p1 = 'Igor';
|
||||||
|
|
||||||
|
$rootScope.viewCount = 0;
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(element.text()).toBe('Nobody is viewing.');
|
||||||
|
|
||||||
|
$rootScope.viewCount = 1;
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(element.text()).toBe('Igor is viewing.');
|
||||||
|
|
||||||
|
$rootScope.viewCount = 2;
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(element.text()).toBe('Igor and one other person are viewing.');
|
||||||
|
|
||||||
|
$rootScope.viewCount = 3;
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(element.text()).toBe('Igor and 2 other people are viewing.');
|
||||||
|
});
|
||||||
|
})
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1108,7 +1108,7 @@ describe('select', function() {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
describe('OPTION value', function() {
|
describe('option', function() {
|
||||||
|
|
||||||
it('should populate value attribute on OPTION', function() {
|
it('should populate value attribute on OPTION', function() {
|
||||||
compile('<select ng-model="x"><option selected>abc</option></select>');
|
compile('<select ng-model="x"><option selected>abc</option></select>');
|
||||||
|
|
@ -1125,5 +1125,18 @@ describe('select', function() {
|
||||||
compile('<select ng-model="x"><option>hello</select>');
|
compile('<select ng-model="x"><option>hello</select>');
|
||||||
expect(element).toEqualSelect(['hello']);
|
expect(element).toEqualSelect(['hello']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not blow up when option directive is found inside of a datalist',
|
||||||
|
inject(function($compile, $rootScope) {
|
||||||
|
var element = $compile('<div>' +
|
||||||
|
'<datalist><option>some val</option></datalist>' +
|
||||||
|
'<span>{{foo}}</span>' +
|
||||||
|
'</div>')($rootScope);
|
||||||
|
|
||||||
|
$rootScope.foo = 'success';
|
||||||
|
$rootScope.$digest();
|
||||||
|
expect(element.find('span').text()).toBe('success');
|
||||||
|
dealoc(element);
|
||||||
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -31,18 +31,6 @@ describe('$interpolate', function() {
|
||||||
expect($interpolate('Hello {{name}}!')($rootScope)).toEqual('Hello Misko!');
|
expect($interpolate('Hello {{name}}!')($rootScope)).toEqual('Hello Misko!');
|
||||||
}));
|
}));
|
||||||
|
|
||||||
describe('provider', function() {
|
|
||||||
beforeEach(module(function($interpolateProvider) {
|
|
||||||
$interpolateProvider.startSymbol('--');
|
|
||||||
$interpolateProvider.endSymbol('--');
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should not get confused with same markers', inject(function($interpolate) {
|
|
||||||
expect($interpolate('---').parts).toEqual(['---']);
|
|
||||||
expect($interpolate('----')()).toEqual('');
|
|
||||||
expect($interpolate('--1--')()).toEqual('1');
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('parseBindings', function() {
|
describe('parseBindings', function() {
|
||||||
it('should Parse Text With No Bindings', inject(function($interpolate) {
|
it('should Parse Text With No Bindings', inject(function($interpolate) {
|
||||||
|
|
@ -110,4 +98,56 @@ describe('$interpolate', function() {
|
||||||
expect(parts[2]).toEqual('C\nD"');
|
expect(parts[2]).toEqual('C\nD"');
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('startSymbol', function() {
|
||||||
|
|
||||||
|
beforeEach(module(function($interpolateProvider) {
|
||||||
|
expect($interpolateProvider.startSymbol()).toBe('{{');
|
||||||
|
$interpolateProvider.startSymbol('((');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should expose the startSymbol in config phase', module(function($interpolateProvider) {
|
||||||
|
expect($interpolateProvider.startSymbol()).toBe('((');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should expose the startSymbol in run phase', inject(function($interpolate) {
|
||||||
|
expect($interpolate.startSymbol()).toBe('((');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should not get confused by matching start and end symbols', function() {
|
||||||
|
module(function($interpolateProvider) {
|
||||||
|
$interpolateProvider.startSymbol('--');
|
||||||
|
$interpolateProvider.endSymbol('--');
|
||||||
|
});
|
||||||
|
|
||||||
|
inject(function($interpolate) {
|
||||||
|
expect($interpolate('---').parts).toEqual(['---']);
|
||||||
|
expect($interpolate('----')()).toEqual('');
|
||||||
|
expect($interpolate('--1--')()).toEqual('1');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
describe('endSymbol', function() {
|
||||||
|
|
||||||
|
beforeEach(module(function($interpolateProvider) {
|
||||||
|
expect($interpolateProvider.endSymbol()).toBe('}}');
|
||||||
|
$interpolateProvider.endSymbol('))');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should expose the endSymbol in config phase', module(function($interpolateProvider) {
|
||||||
|
expect($interpolateProvider.endSymbol()).toBe('))');
|
||||||
|
}));
|
||||||
|
|
||||||
|
|
||||||
|
it('should expose the endSymbol in run phase', inject(function($interpolate) {
|
||||||
|
expect($interpolate.endSymbol()).toBe('))');
|
||||||
|
}));
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1038,7 +1038,8 @@ describe('$location', function() {
|
||||||
bind: function(event, handler) {
|
bind: function(event, handler) {
|
||||||
expect(event).toEqual('click');
|
expect(event).toEqual('click');
|
||||||
clickHandler = handler;
|
clickHandler = handler;
|
||||||
}
|
},
|
||||||
|
unbind: angular.noop
|
||||||
});
|
});
|
||||||
return function($browser) {
|
return function($browser) {
|
||||||
$browser.url(base = 'http://server/');
|
$browser.url(base = 'http://server/');
|
||||||
|
|
@ -1067,7 +1068,8 @@ describe('$location', function() {
|
||||||
bind: function(event, handler) {
|
bind: function(event, handler) {
|
||||||
expect(event).toEqual('click');
|
expect(event).toEqual('click');
|
||||||
clickHandler = handler;
|
clickHandler = handler;
|
||||||
}
|
},
|
||||||
|
unbind: angular.noop
|
||||||
});
|
});
|
||||||
return function($browser) {
|
return function($browser) {
|
||||||
$browser.url(base = 'http://server/');
|
$browser.url(base = 'http://server/');
|
||||||
|
|
|
||||||
|
|
@ -182,7 +182,7 @@ describe('Scope', function() {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
||||||
it('should repeat watch cycle from the root elemnt', inject(function($rootScope) {
|
it('should repeat watch cycle from the root element', inject(function($rootScope) {
|
||||||
var log = '';
|
var log = '';
|
||||||
var child = $rootScope.$new();
|
var child = $rootScope.$new();
|
||||||
$rootScope.$watch(function() { log += 'a'; });
|
$rootScope.$watch(function() { log += 'a'; });
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
<meta http-equiv="expires" content="0">
|
||||||
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng-autotest></script>
|
<script type="text/javascript" src="../../../src/scenario/angular-bootstrap.js" ng-autotest></script>
|
||||||
<script type="text/javascript" src="widgets-scenario.js"></script>
|
<script type="text/javascript" src="widgets-scenario.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
# AngularJS build config file
|
# AngularJS build config file
|
||||||
---
|
---
|
||||||
version: 1.0.2-snapshot
|
version: 1.0.2
|
||||||
codename: debilitating-awesomeness
|
codename: debilitating-awesomeness
|
||||||
|
stable: 1.0.1
|
||||||
|
|
|
||||||