mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
Developer guide documentation
This commit is contained in:
parent
9fd3dfe49d
commit
ed768ebc53
10 changed files with 349 additions and 10 deletions
27
docs/guide.contribute.ngdoc
Normal file
27
docs/guide.contribute.ngdoc
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Contributing
|
||||
@description
|
||||
|
||||
# Open Source
|
||||
Angular is an open source project licensed under the
|
||||
{@link http://github.com/angular/angular.js/blob/master/LICENSE MIT license}. We welcome any
|
||||
contributions from the community, but in order to make the contribution process manageable, we ask
|
||||
you to follow the following guidelines:
|
||||
|
||||
# Source Code
|
||||
* Discuss any major changes on our {@link http://groups.google.com/group/angular mailing list}.
|
||||
For small changes and bugfixes, just go ahead and craft your patch and submit it.
|
||||
* Use coding style described
|
||||
{@link http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml here}.
|
||||
* To submit any changes, we ask you to use {@link http://github.com}
|
||||
* Create a github {@link https://github.com/signup/free account}
|
||||
* Clone the {@link http://github.com/angular/angular.js main angular repository}
|
||||
* Create a new branch off of the master (`git branch my-fix-branch`)
|
||||
* Switch to the branch (`git checkout my-fix-branch`), make your changes and commit (`git commit -a`)
|
||||
* For any new features or regressions we require a test(s) to be submitted with the change
|
||||
* Run js lint (`rake lint`) and fix any warnings or errors
|
||||
* Push your branch to github (`git push origin my-fix-branch`)
|
||||
* Send a pull request via github into `angular:master`
|
||||
* Once the patch is reviewed and merged, you can delete your branch (`git push origin :my-fix-branch; git checkout master; git branch -D my-fix-branch`)
|
||||
* TADA!
|
||||
46
docs/guide.css.ngdoc
Normal file
46
docs/guide.css.ngdoc
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: CSS
|
||||
@description
|
||||
|
||||
# CSS
|
||||
angular includes built-in CSS classes, which in turn have predefined CSS styles.
|
||||
|
||||
# Built-in CSS classes
|
||||
|
||||
## `ng-exception`
|
||||
|
||||
**Usage:** angular applies this class to a DOM element if that element contains an Expression that
|
||||
threw an exception when evaluated.
|
||||
|
||||
**Styling:** The built-in styling of the ng-exception class displays an error message surrounded
|
||||
by a solid red border, for example:
|
||||
|
||||
> <div class="ng-exception">Error message</div>
|
||||
|
||||
|
||||
|
||||
You can try to evaluate malformed expressions in {@link angualr.expression expression} to see the
|
||||
`ng-exception` class' styling.
|
||||
|
||||
## `ng-validation-error`
|
||||
|
||||
**Usage:** angular applies this class to an input widget element if that element's input does not
|
||||
pass validation. Note that you set the validation criteria on the input widget element using the
|
||||
Ng:validate or Ng:required directives.
|
||||
|
||||
**Styling:** The built-in styling of the ng-validation-error class turns the border of the input
|
||||
box red and includes a hovering UI element that includes more details of the validation error. You
|
||||
can see an example in {@link angular.widget.@ng:validate ng:validate example}.
|
||||
|
||||
## How to override the styles for built-in classes
|
||||
|
||||
To override the styles for these built-in classes, you can do any of the following:
|
||||
|
||||
Download the source code, edit angular.css, and host the source on your own server.
|
||||
Create a local css file, overriding any styles that you'd like, and link to it from your HTML file
|
||||
as you normally would:
|
||||
|
||||
<pre>
|
||||
<link href="yourfile.css" rel="stylesheet" type="text/css">
|
||||
</pre>
|
||||
35
docs/guide.downloading.ngdoc
Normal file
35
docs/guide.downloading.ngdoc
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Downloading
|
||||
@description
|
||||
|
||||
# Downloading
|
||||
Follow these steps to download, compile, and host angular.js on your own server:
|
||||
|
||||
## Step 0
|
||||
|
||||
If you don't already have Rake (Ruby Make) installed, download and install it from
|
||||
http://rake.rubyforge.org/.
|
||||
|
||||
## Step 1
|
||||
|
||||
Download the angular source code from GitHub: http://github.com/angular/angular.js.
|
||||
|
||||
## Step 2
|
||||
|
||||
The source code should include a Rakefile. Compile the source by typing rake compile.
|
||||
|
||||
## Step 3
|
||||
|
||||
Host the files on your server. Look through your source tree and make sure that the css and js
|
||||
directories are parallel (i.e. share a common root node).
|
||||
|
||||
In the js directory you should see these different versions of the angular bootstrap code:
|
||||
|
||||
* **angular-?.?.?.js** - this file is unobfuscated, uncompressed, and human-readable. Note that
|
||||
despite the name of the file, there is no additional functionality built in to help you debug
|
||||
your application; it has the prefix debug because you can read the source code.
|
||||
* **angular-?.?.?.min.js** - this is a compressed and obfuscated version of `angular-?.?.?.js`.
|
||||
You might want to use this version if you want to load a smaller but functionally equivalent
|
||||
version of the code in your application. Note: this minified version was created using the
|
||||
Closure Compiler.
|
||||
207
docs/guide.expression.ngdoc
Normal file
207
docs/guide.expression.ngdoc
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Expression
|
||||
@description
|
||||
|
||||
# Expressions
|
||||
Expressions are the bindings that you write in HTML and embed in templates in order to create
|
||||
views in angular. They are not equivalent to JavaScript expressions.
|
||||
|
||||
For example, these are all valid expressions in angular:
|
||||
|
||||
* `1+2={{1+2}}`
|
||||
* `3*10|currency`
|
||||
* `Hello {{name}}!`
|
||||
* `Hello {{'World'}}!`
|
||||
|
||||
|
||||
# angular expressions vs. JS expressions
|
||||
It might be tempting to think of angular view expressions as JavaScript expressions, but that is
|
||||
not entirely correct. angular does not use a simple JavaScript eval of the expression text. You
|
||||
can think of angular expressions as JavaScript expressions with these differences:
|
||||
|
||||
* **Attribute Evaluation:** evaluation of all attributes are against the current scope, not to
|
||||
the global window as in JavaScript.
|
||||
* **Forgiving:** expression evaluation is forgiving to undefined and null, unlike in JavaScript.
|
||||
* **No Control Flow Statements:** you cannot do the following from an angular expression:
|
||||
conditionals, loops, or throw.
|
||||
* **Type Augmentation:** the scope expression evaluator augments built-in types.
|
||||
* **Filters:** you can add filters to an expression, for example to convert raw data into a
|
||||
human-readable format.
|
||||
* **The $:** angular reserves this prefix to differentiate its API names from others.
|
||||
|
||||
If you want to run arbitrary JavaScript code, make it a controller method and call that. If you
|
||||
want to eval an angular expression from JavaScript, use the Scope:$eval() method.
|
||||
|
||||
## Example
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
1+2={{1+2}}
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should calculate expression in binding', function(){
|
||||
expect(binding('1+2')).toEqual('3');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
You can try evaluating different expressions here:
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<div ng:init="exprs=[]" class="expressions">
|
||||
Expression:
|
||||
<input type='text' name="expr" value="3*10|currency" size="80"/>
|
||||
<button ng:click="exprs.$add(expr)">Evaluate</button>
|
||||
<ul>
|
||||
<li ng:repeat="expr in exprs">
|
||||
[ <a href="" ng:click="exprs.$remove(expr)">X</a> ]
|
||||
<tt>{{expr}}</tt> => <span ng:bind="$parent.$eval(expr)"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should allow user expression testing', function(){
|
||||
element('.expressions :button').click();
|
||||
var li = using('.expressions ul').repeater('li');
|
||||
expect(li.count()).toBe(1);
|
||||
expect(li.row(0)).toEqual(["3*10|currency", "$30.00"]);
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
# Attribute Evaluation
|
||||
|
||||
Evaluation of all attributes are against the current scope. Unlike JavaScript, where names
|
||||
default to global window properties, angular expressions have to use $window to refer to the
|
||||
global object. E.g. if you want to call alert(), which is defined on window, an expression must
|
||||
use $window.alert(). This is done intentionally to prevent accidental access to the global state
|
||||
(a common source of subtle bugs).
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<div class="example2" ng:init="$window = $service('$window')">
|
||||
Name: <input name="name" type="text" value="World"/>
|
||||
<button ng:click="($window.mockWindow || $window).alert('Hello ' + name)">Greet</button>
|
||||
</div>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should calculate expression in binding', function(){
|
||||
var alertText;
|
||||
this.addFutureAction('set mock', function($window, $document, done) {
|
||||
$window.mockWindow = {
|
||||
alert: function(text){ alertText = text; }
|
||||
};
|
||||
done();
|
||||
});
|
||||
element(':button:contains(Greet)').click();
|
||||
expect(this.addFuture('alert text', function(done) {
|
||||
done(null, alertText);
|
||||
})).toBe('Hello World');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
## Forgiving
|
||||
|
||||
Expression evaluation is forgiving to undefined and null. In JavaScript, evaluating a.b.c throws
|
||||
an exception if a is not an object. While this makes sense for a general purpose language, the
|
||||
expression evaluations are primarily used for data binding, which often look like this: `{{a.b.c}}`.
|
||||
It makes more sense to show nothing than to throw an exception if a is undefined (e.g. perhaps
|
||||
we are waiting for the server response, and it will become defined soon). If expression
|
||||
evaluation wasn't forgiving we'd have to write bindings that clutter the code, for example:
|
||||
`{{((a||{}).b||{}).c}}`
|
||||
|
||||
Similarly, invoking a function a.b.c() on undefined or null simply returns undefined.
|
||||
|
||||
Assignments work the same way in reverse. a.b.c = 10 creates the intermediary objects even if a
|
||||
is undefined.
|
||||
|
||||
|
||||
## No Control Flow Statements
|
||||
|
||||
You cannot write a control flow statement in an expression. The reason behind this is core to
|
||||
the angular philosophy that application logic should be in controllers, not in the view. If you
|
||||
need a conditional (including ternary operators), loop, or to throw from a view expression,
|
||||
delegate to a JavaScript method instead.
|
||||
|
||||
|
||||
## Type Augmentation
|
||||
|
||||
Built-in types have methods like [].push(), but the richness of these methods is limited. Consider
|
||||
the example below, which allows you to do a simple search over a canned set of contacts. The
|
||||
example would be much more complicated if we did not have the Array:$filter(). There is no
|
||||
built-in method on Array called $filter and angular doesn't add it to Array.prototype because that
|
||||
could collide with other JavaScript frameworks.
|
||||
|
||||
For this reason the scope expression evaluator augments the built-in types to make them act like
|
||||
they have extra methods. The actual method for $filter() is angular.Array.filter(). You can call
|
||||
it from JavaScript.
|
||||
|
||||
Extensions: You can further extend the expression vocabulary by adding new methods to
|
||||
`angular.Array` or `angular.String`, etc.
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
<div ng:init="friends = [
|
||||
{name:'John', phone:'555-1212'},
|
||||
{name:'Mary', phone:'555-9876'},
|
||||
{name:'Mike', phone:'555-4321'},
|
||||
{name:'Adam', phone:'555-5678'},
|
||||
{name:'Julie', phone:'555-8765'}]"></div>
|
||||
Search: <input name="searchText"/>
|
||||
<table class="example3">
|
||||
<tr><th>Name</th><th>Phone</th><tr>
|
||||
<tr ng:repeat="friend in friends.$filter(searchText)">
|
||||
<td>{{friend.name}}</td>
|
||||
<td>{{friend.phone}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should filter the list', function(){
|
||||
var tr = using('table.example3').repeater('tr.ng-attr-widget');
|
||||
expect(tr.count()).toBe(5);
|
||||
input('searchText').enter('a');
|
||||
expect(tr.count()).toBe(2);
|
||||
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
## Filters
|
||||
|
||||
When presenting data to the user, you might need to convert the data from its raw format to a
|
||||
user-friendly format. For example, you might have a data object that needs to be formatted
|
||||
according to the locale before displaying it to the user. You can pass expressions through a
|
||||
chain of filters like this:
|
||||
|
||||
<pre>
|
||||
name | uppercase
|
||||
</pre>
|
||||
|
||||
The expression evaluator simply passes the value of name to angular.filter.uppercase.
|
||||
|
||||
Chain filters using this syntax:
|
||||
|
||||
<pre>
|
||||
value | filter1 | filter2
|
||||
</pre>
|
||||
|
||||
You can also pass colon-delimited arguments to filters, for example, to display the number 123
|
||||
with 2 decimal points: 123 | number:2
|
||||
|
||||
# The $
|
||||
|
||||
You might be wondering, what is the significance of the $ prefix? It is simply a prefix that
|
||||
angular chooses to differentiate its API names from others. If angular didn't use $, then
|
||||
evaluating a.length() would return undefined because neither a nor angular define such a property.
|
||||
Consider that in a future version of angular we might choose to add a length method, in which case
|
||||
the behavior of the expression would change. Worse yet, you the developer could create a length
|
||||
property and then we would have collision. This problem exists because angular augments existing
|
||||
objects with additional behavior. By prefixing its additions with $ we are reserving our namespace
|
||||
so that angular developers and developers who use angular can develop in harmony without
|
||||
collisions.
|
||||
|
||||
|
||||
|
|
@ -34,3 +34,4 @@
|
|||
* service:$browser(mock)
|
||||
* {@link guide.downloading Downloading} - How to download, compile, and host the angular
|
||||
environment on your own server.
|
||||
* {@link guide.contribute Contributing} - How to contribute to angular project.
|
||||
|
|
|
|||
8
docs/guide.testing.ngdoc
Normal file
8
docs/guide.testing.ngdoc
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Testing
|
||||
@description
|
||||
|
||||
# Testing Angular Applications
|
||||
|
||||
to be written...
|
||||
|
|
@ -319,6 +319,7 @@ describe('ngdoc', function(){
|
|||
var doc = new Doc("@description " +
|
||||
'foo {@link angular.foo}\n\n da {@link angular.foo bar foo bar } \n\n' +
|
||||
'dad{@link angular.foo}\n\n' +
|
||||
'external{@link http://angularjs.org}\n\n' +
|
||||
'{@link angular.directive.ng:foo ng:foo}');
|
||||
doc.parse();
|
||||
expect(doc.description).
|
||||
|
|
@ -329,6 +330,8 @@ describe('ngdoc', function(){
|
|||
toContain('dad<a href="#!angular.foo"><code>angular.foo</code></a>');
|
||||
expect(doc.description).
|
||||
toContain('<a href="#!angular.directive.ng:foo"><code>ng:foo</code></a>');
|
||||
expect(doc.description).
|
||||
toContain('<a href="http://angularjs.org">http://angularjs.org</a>');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
@ -357,12 +360,16 @@ describe('ngdoc', function(){
|
|||
});
|
||||
|
||||
it('should render description in related method', function(){
|
||||
var doc = new Doc();
|
||||
var doc = new Doc('').parse();
|
||||
doc.ngdoc = 'service';
|
||||
doc.methods = [new Doc('@ngdoc method\n@exampleDescription MDesc\n@example MExmp').parse()];
|
||||
doc.properties = [new Doc('@ngdoc property\n@exampleDescription PDesc\n@example PExmp').parse()];
|
||||
expect(doc.html()).toContain('<p>MDesc</p><div ng:non-bindable=""><pre class="brush: js; html-script: true;">MExmp</pre>');
|
||||
expect(doc.html()).toContain('<p>PDesc</p><div ng:non-bindable=""><pre class="brush: js; html-script: true;">PExmp</pre>');
|
||||
doc.methods = [
|
||||
new Doc('@ngdoc method\n@exampleDescription MDesc\n@example MExmp').parse()];
|
||||
doc.properties = [
|
||||
new Doc('@ngdoc property\n@exampleDescription PDesc\n@example PExmp').parse()];
|
||||
expect(doc.html()).toContain('<p>MDesc</p><div ng:non-bindable="">' +
|
||||
'<pre class="brush: js; html-script: true;">MExmp</pre>');
|
||||
expect(doc.html()).toContain('<p>PDesc</p><div ng:non-bindable="">' +
|
||||
'<pre class="brush: js; html-script: true;">PExmp</pre>');
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ Doc.prototype = {
|
|||
description: markdown(text.replace(match[0], match[2]))
|
||||
};
|
||||
} else if(atName == 'description') {
|
||||
text.replace(/<doc:scenario>([\s\S]*)<\/doc:scenario>/mi,
|
||||
text.replace(/<doc:scenario>([\s\S]*?)<\/doc:scenario>/gmi,
|
||||
function(_, scenario){
|
||||
self.scenarios.push(scenario);
|
||||
});
|
||||
|
|
@ -154,7 +154,7 @@ Doc.prototype = {
|
|||
throw new Error("Don't know how to format @ngdoc: " + self.ngdoc);
|
||||
}).call(self, dom);
|
||||
|
||||
dom.example(self.exampleDescription, self.example, self.scenario);
|
||||
dom.example(self.exampleDescription, self.example, self.scenarios[0]);
|
||||
});
|
||||
|
||||
return dom.toString();
|
||||
|
|
@ -438,6 +438,8 @@ Doc.prototype = {
|
|||
|
||||
//////////////////////////////////////////////////////////
|
||||
function markdown (text) {
|
||||
var IS_URL = /^(https?:\/\/|ftps?:\/\/|mailto:)/;
|
||||
var IS_ANGULAR = /^angular\./;
|
||||
if (!text) return text;
|
||||
var parts = text.split(/(<pre>[\s\S]*?<\/pre>|<doc:example>[\s\S]*?<\/doc:example>)/),
|
||||
match;
|
||||
|
|
@ -462,10 +464,10 @@ function markdown (text) {
|
|||
text = text.replace(/<angular\/>/gm, '<tt><angular/></tt>');
|
||||
text = text.replace(/{@link ([^\s}]+)((\s|\n)+(.+?))?\s*}/gm,
|
||||
function(_all, url, _2, _3, title){
|
||||
return '<a href="#!' + url + '">'
|
||||
+ (url.match(/^angular\./) ? '<code>' : '')
|
||||
return '<a href="' + (url.match(IS_URL) ? '' : '#!') + url + '">'
|
||||
+ (url.match(IS_ANGULAR) ? '<code>' : '')
|
||||
+ (title || url)
|
||||
+ (url.match(/^angular\./) ? '</code>' : '')
|
||||
+ (url.match(IS_ANGULAR) ? '</code>' : '')
|
||||
+ '</a>';
|
||||
});
|
||||
text = new Showdown.converter().makeHtml(text);
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@
|
|||
});
|
||||
|
||||
function indent(text) {
|
||||
if (!text) return text;
|
||||
var lines = text.split(/\n/);
|
||||
var lineNo = [];
|
||||
// remove any leading blank lines
|
||||
|
|
|
|||
|
|
@ -40,4 +40,9 @@ function DocsController($location, $browser, $window) {
|
|||
|
||||
}
|
||||
|
||||
// prevent compilation of code
|
||||
angular.widget('code', function(element){
|
||||
element.attr('ng:non-bindable', 'true');
|
||||
});
|
||||
|
||||
SyntaxHighlighter['defaults'].toolbar = false;
|
||||
|
|
|
|||
Loading…
Reference in a new issue