aboutsummaryrefslogtreecommitdiffstats
path: root/docs
diff options
context:
space:
mode:
authorMisko Hevery2011-01-31 11:55:44 -0800
committerMisko Hevery2011-02-01 09:58:37 -0800
commited768ebc53ef6746ca83d81892c22d2e9c3afeef (patch)
tree2835e5ab21d4700724c28d8bf1178ea13e622eae /docs
parent9fd3dfe49d283c136e29bf60c0da6d4fe2aaed3d (diff)
downloadangular.js-ed768ebc53ef6746ca83d81892c22d2e9c3afeef.tar.bz2
Developer guide documentation
Diffstat (limited to 'docs')
-rw-r--r--docs/guide.contribute.ngdoc27
-rw-r--r--docs/guide.css.ngdoc46
-rw-r--r--docs/guide.downloading.ngdoc35
-rw-r--r--docs/guide.expression.ngdoc207
-rw-r--r--docs/guide.ngdoc1
-rw-r--r--docs/guide.testing.ngdoc8
-rw-r--r--docs/spec/ngdocSpec.js17
-rw-r--r--docs/src/ngdoc.js12
-rw-r--r--docs/src/templates/doc_widgets.js1
-rw-r--r--docs/src/templates/docs.js5
10 files changed, 349 insertions, 10 deletions
diff --git a/docs/guide.contribute.ngdoc b/docs/guide.contribute.ngdoc
new file mode 100644
index 00000000..9e50e661
--- /dev/null
+++ b/docs/guide.contribute.ngdoc
@@ -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!
diff --git a/docs/guide.css.ngdoc b/docs/guide.css.ngdoc
new file mode 100644
index 00000000..6e028f30
--- /dev/null
+++ b/docs/guide.css.ngdoc
@@ -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>
diff --git a/docs/guide.downloading.ngdoc b/docs/guide.downloading.ngdoc
new file mode 100644
index 00000000..9f0f2194
--- /dev/null
+++ b/docs/guide.downloading.ngdoc
@@ -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.
diff --git a/docs/guide.expression.ngdoc b/docs/guide.expression.ngdoc
new file mode 100644
index 00000000..421dd9c7
--- /dev/null
+++ b/docs/guide.expression.ngdoc
@@ -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.
+
+
diff --git a/docs/guide.ngdoc b/docs/guide.ngdoc
index b1ac143e..fd5d05df 100644
--- a/docs/guide.ngdoc
+++ b/docs/guide.ngdoc
@@ -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.
diff --git a/docs/guide.testing.ngdoc b/docs/guide.testing.ngdoc
new file mode 100644
index 00000000..bb3a1441
--- /dev/null
+++ b/docs/guide.testing.ngdoc
@@ -0,0 +1,8 @@
+@workInProgress
+@ngdoc overview
+@name Developer Guide: Testing
+@description
+
+# Testing Angular Applications
+
+to be written...
diff --git a/docs/spec/ngdocSpec.js b/docs/spec/ngdocSpec.js
index 9d84ee7e..d912bf3a 100644
--- a/docs/spec/ngdocSpec.js
+++ b/docs/spec/ngdocSpec.js
@@ -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>');
});
});
diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js
index e01d9ccf..a3a037cd 100644
--- a/docs/src/ngdoc.js
+++ b/docs/src/ngdoc.js
@@ -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>&lt;angular/&gt;</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);
diff --git a/docs/src/templates/doc_widgets.js b/docs/src/templates/doc_widgets.js
index 39b9ff48..bfa8e5d0 100644
--- a/docs/src/templates/doc_widgets.js
+++ b/docs/src/templates/doc_widgets.js
@@ -56,6 +56,7 @@
});
function indent(text) {
+ if (!text) return text;
var lines = text.split(/\n/);
var lineNo = [];
// remove any leading blank lines
diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js
index aaea8c9d..ab96a699 100644
--- a/docs/src/templates/docs.js
+++ b/docs/src/templates/docs.js
@@ -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;