mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-17 07:40:22 +00:00
Added part of guide documentation and supporting changes to doc generator
This commit is contained in:
parent
8682befc72
commit
bd33f60276
18 changed files with 863 additions and 129 deletions
97
docs/guide.bootstrap.ngdoc
Normal file
97
docs/guide.bootstrap.ngdoc
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Bootstrap
|
||||
@description
|
||||
|
||||
# Bootstrap
|
||||
This section explains how to bootstrap your application to the angular environment using either
|
||||
the `angular.js` or `angular.min.js` script.
|
||||
|
||||
## The bootstrap code
|
||||
|
||||
Note that there are two versions of the bootstrap code that you can use:
|
||||
|
||||
* `angular-0.0.0.js` - this file is unobfuscated, uncompressed, and thus human-readable.
|
||||
* `angular-0.0.0.min.js` - this is a compressed and obfuscated version of angular-debug.js.
|
||||
|
||||
In this section and throughout the Developer Guide, feel free to use `angular.min.js` instead of
|
||||
`angular.js` when working through code examples.
|
||||
|
||||
## ng:autobind
|
||||
|
||||
The simplest way to get an angular application up and running is by inserting a script tag in your
|
||||
HTML file that bootstraps the `angular.js` code and uses the special `ng:autobind` attribute,
|
||||
like in this snippet of HTML:
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
Hello {{'World'}}!
|
||||
</doc:source>
|
||||
</doc:example>
|
||||
|
||||
The `ng:autobind` attribute tells angular to compile and manage the whole HTML document. The
|
||||
compilation occurs in the page's onLoad handler. Note that you don't need to explicitly add an
|
||||
onLoad event; auto bind mode takes care of all the magic for you.
|
||||
|
||||
## Manual bind
|
||||
|
||||
Using autobind mode is a handy way to start using angular, but advanced users who want more
|
||||
control over the initialization process might prefer to use manual bind mode instead.
|
||||
|
||||
The best way to get started with manual bind mode is to look at the magic behind `ng:autobind`
|
||||
by writing out each step of the autobind process explicitly. Note that the following code is
|
||||
equivalent to the code in the previous section.
|
||||
|
||||
<pre>
|
||||
<!DOCTYPE HTML>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<script type="text/javascript" src="http://code.angularjs.org/angular-0.0.0.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
(function(window, previousOnLoad){
|
||||
window.onload = function(){
|
||||
try { (previousOnLoad||angular.noop)(); } catch(e) {}
|
||||
angular.compile(window.document).$init();
|
||||
};
|
||||
})(window, window.onload);
|
||||
</script>
|
||||
<body>
|
||||
Hello {{'World'}}!
|
||||
</body>
|
||||
</html>
|
||||
</pre>
|
||||
|
||||
This is the sequence that your code should follow if you're writing your own manual binding code:
|
||||
|
||||
* After the page is loaded, find the root of the HTML template, which is typically the root of
|
||||
the document.
|
||||
* Run the HTML compiler, which converts the templates into an executable, bi-directionally
|
||||
bound application.
|
||||
|
||||
|
||||
# XML Namespace
|
||||
|
||||
**IMPORTANT:** When using angular you must declare the `ng` namespace using the `xmlns` tag.
|
||||
If you don't declare the namespace, Internet Explorer does not render widgets properly.
|
||||
|
||||
<pre>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
</pre>
|
||||
|
||||
|
||||
# Create your own namespace
|
||||
|
||||
If you want to define your own widgets, you must create your own namespace and use that namespace
|
||||
to form the fully qualified widget name. For example, you could map the alias my to your domain
|
||||
and create a widget called my:widget. To create your own namespace, simply add another xmlsn tag
|
||||
to your page, create an alias, and set it to your unique domain:
|
||||
|
||||
<pre>
|
||||
<html xmlns:my="http://mydomain.com">
|
||||
</pre>
|
||||
|
||||
|
||||
# Global Object
|
||||
|
||||
The angular script creates a single global variable `angular` in the global namespace. All APIs are
|
||||
bound to fields of this global object.
|
||||
|
||||
163
docs/guide.compiler.ngdoc
Normal file
163
docs/guide.compiler.ngdoc
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Compiler
|
||||
@description
|
||||
|
||||
#Compiler
|
||||
|
||||
While angular might look like just a cool way to build web applications, the core of angular is
|
||||
actually an HTML compiler. The default HTML transformations that this compiler provides are useful
|
||||
for building generic apps, but you can also use them to create a domain-specific language for
|
||||
building specific types of web applications.
|
||||
|
||||
The compiler allows you to add behavior to existing HTML through widgets, directives, and text
|
||||
markup.
|
||||
|
||||
All of this compilation happens in the web browser, meaning no server is involved.
|
||||
|
||||
# The compilation process
|
||||
This section describes the steps that angular's HTML compiler goes through. If you use
|
||||
`ng:autobind` in your application, this compilation process happens automatically when the
|
||||
application is initialized (e.g. when the user loads the app in a browser). If you're an advanced
|
||||
user using manual bind mode, you can decide when and how often the compilation happens.
|
||||
|
||||
First, a bit of background of what the compilation step is for. Every type of
|
||||
{@link angular.widget widget}, {@link angular.markup markup}, and
|
||||
{@link angular.directive directive} in angular is defined with a compile function, and that
|
||||
compile function returns an optional link function. Here is the relationship between the two:
|
||||
|
||||
* **compile function** - registers a listener for the widget, markup, or directive's expression.
|
||||
This function is called exactly once.
|
||||
* **link function** - sets up the listener. This function can be called multiple times, once per
|
||||
cloned DOM element (e.g. repeating element).
|
||||
|
||||
Note that angular's built-in widgets, markup, and directives have predefined compile and link
|
||||
functions that you don't need to modify. However, if you're writing your own widgets, markup, or
|
||||
directives, you write compile and link functions. Refer to the Compiler API for more information.
|
||||
|
||||
When the HTML compiler compiles a page, it goes through 3 phases: Compile, Create Root Scope, and
|
||||
Link.
|
||||
|
||||
## 1. Compile Phase
|
||||
|
||||
* Recursively traverse the DOM, depth-first.
|
||||
* Look for a matching compile function of type widget, then markup, then directive.
|
||||
* If a compile function is found then execute it.
|
||||
* When the compile function completes, it should return a link function. Aggregate this link
|
||||
function with all link functions returned previously by step 1c.
|
||||
* Repeat steps 1c and 1d for all compile functions found. The result of the compilation step is
|
||||
the aggregate link function, which comprises all of the individual link functions.
|
||||
|
||||
## 2. Create Root Scope
|
||||
|
||||
* Inject all of the services into the root scope.
|
||||
|
||||
## 3. Link Phase
|
||||
|
||||
* Execute the aggregate link function with the root scope. The aggregate link function calls all
|
||||
the individual link functions that were generated in the compile phase.
|
||||
* If there are any clones of the DOM caused by repeating elements, call the link function multiple
|
||||
times, one for each repeating item.
|
||||
|
||||
Note that while the compile function is executed exactly once, the link function can be executed
|
||||
multiple times: once for each iteration in a repeater.
|
||||
|
||||
# Example
|
||||
|
||||
The compilation process is best understood through example. Let's say that in your namespace my,
|
||||
you want to create a new DOM element <my:greeter/>, which should display a greeting.
|
||||
|
||||
If we want this HTML source:
|
||||
|
||||
<pre>
|
||||
<div ng:init="salutation='Hello'; name='World'">
|
||||
<my:greeter salutation="salutation" name="name"/>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
To produce this DOM:
|
||||
|
||||
<pre>
|
||||
<div ng:init="salutation='Hello'; name='World'">
|
||||
<my:greeter salutation="salutation" name="name"/>
|
||||
<span class="salutation">Hello</span>
|
||||
<span class="name">World</span>!
|
||||
</my:greeter>
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
Write this widget definition (assuming you've already declared the my namespace in the page):
|
||||
|
||||
|
||||
<pre>
|
||||
angular.widget('my:greeter', function(compileElement){
|
||||
var compiler = this;
|
||||
compileElement.css('display', 'block');
|
||||
var salutationExp = compileElement.attr('salutation');
|
||||
var nameExp = compileElement.attr('name');
|
||||
return function(linkElement){
|
||||
var salutationSpan = angular.element('<span class="salutation"></span');
|
||||
var nameSpan = angular.element('<span class="name"></span>');
|
||||
linkElement.append(salutationSpan);
|
||||
linkElement.append(compiler.text(' '));
|
||||
linkElement.append(nameSpan);
|
||||
linkElement.append(compiler.text('!'));
|
||||
this.$watch(salutationExp, function(value){
|
||||
salutationSpan.text(value);
|
||||
});
|
||||
this.$watch(nameExp, function(value){
|
||||
nameSpan.text(value);
|
||||
});
|
||||
};
|
||||
});
|
||||
</pre>
|
||||
|
||||
Note: For more about widgets, see {@link angular.widget Widget}.
|
||||
|
||||
## Compilation process for this example
|
||||
|
||||
Here are the steps that the compiler goes through for the page that contains this widget definition:
|
||||
|
||||
### Compile Phase
|
||||
|
||||
* Recursively traverse the DOM depth-first.
|
||||
* Find the angular.widget definition.
|
||||
* Find and execute the widget's compileElement function, which includes the following steps:
|
||||
* Add a style element with attribute display: block; to the template DOM so that the browser
|
||||
knows to treat the element as block element for rendering. (Note: because this style element
|
||||
was added on the template compileElement, this style is automatically applied to any clones
|
||||
of the template (i.e. any repeating elements)).
|
||||
* Extract the salutation and name HTML attributes as angular expressions.
|
||||
* Return the aggregate link function, which includes just one link function in this example.
|
||||
|
||||
### Link Phase
|
||||
|
||||
* Execute the aggregate link function, which includes the following steps:
|
||||
* Create a <span> element set to the salutation class
|
||||
* Create a <span> element set to the name class.
|
||||
* Add the span elements to the linkElement. (Note: be careful not to add them to the
|
||||
compileElement, because that's the template.)
|
||||
* Set up watches on the expressions. When an expression changes, copy the data to the
|
||||
corresponding spans.
|
||||
|
||||
|
||||
## Compiler API
|
||||
|
||||
If you define your own widgets, markup, or directives, you need to access the compiler API.
|
||||
This section describes the methods on the compiler that you can call.
|
||||
|
||||
Note: As of 12 August 2010, these methods are subject to change.
|
||||
|
||||
Recall that the compile function's this is a reference to the compiler.
|
||||
|
||||
* `compile(element)` - returns `linker` - Invoke new instance of compiler to compile a DOM element
|
||||
and return a linker function. You can apply the linker function to the original element or a
|
||||
clone of the original element. The linker function returns a scope.
|
||||
* `comment(commentText)` - returns `element` - Create a comment element.
|
||||
* `element(elementName)` - returns `element` - Create an element by name.
|
||||
* `text(text)` - returns `element` - Create a text element.
|
||||
* `descend([set])` - returns `descend` - State Get or set the current descend state. If true the
|
||||
compiler will descend to children elements.
|
||||
* `directives([set])` - returns `directive` - State Get or set the current directives processing
|
||||
state. The compiler will process directives only when directives set to true.
|
||||
|
||||
41
docs/guide.data-binding.ngdoc
Normal file
41
docs/guide.data-binding.ngdoc
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Data Binding
|
||||
@description
|
||||
|
||||
# Data Binding
|
||||
|
||||
Data-binding allows you to treat the model as the single-source-of-truth of your application, and
|
||||
consider the view as only a projection of the model, at all times. The process of copying the model
|
||||
values to the view, and any changes to the view by the user to the model, is known as data-binding.
|
||||
|
||||
## Classical Template Systems
|
||||
|
||||
<img class="right" src="img/One_Way_Data_Binding.png"/>
|
||||
At the highest level, angular looks 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: two-way data binding.
|
||||
|
||||
Most templating systems bind data in only one direction: they merge a template and model together
|
||||
into a view, as illustrated in the diagram to the right. After the merge occurs, any changes to
|
||||
the model or in related sections of the view are NOT automatically reflected in the view. Worse,
|
||||
any changes that the user makes to the view are not reflected in the model. This means that the
|
||||
developer has to write code that constantly syncs the view with the model and the model with the
|
||||
view.
|
||||
|
||||
|
||||
# angular Template Systems
|
||||
<img class="right" src="img/Two_Way_Data_Binding.png"/>
|
||||
The way angular templates works is different, as illustrated in the diagram on the right. They are
|
||||
different because first the template (which is the uncompiled HTML along with any additional markup
|
||||
or 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 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 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
|
||||
view and unaware of it. This makes testing a snap because it is easy to test your controller in
|
||||
isolation without the view and the related DOM/browser dependency.
|
||||
|
||||
For details about how data binding works in angular, see {@link angular.scope Scope}.
|
||||
36
docs/guide.ngdoc
Normal file
36
docs/guide.ngdoc
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide
|
||||
@description
|
||||
|
||||
* {@link guide.overview Overview} - An overview of angular, including its philosophy and how it
|
||||
works.
|
||||
* {@link guide.bootstrap Bootstrap} - How to bootstrap your application to the angular environment.
|
||||
* {@link guide.template Template} - How to define your application's view using HTML, CSS, and
|
||||
other built-in angular constructs.
|
||||
* {@link guide.compiler Compiler} - All about the HTML compiler that's at the core of angular.
|
||||
* {@link angular.directive Directive} - How to use XML attributes to augment an existing DOM
|
||||
element.
|
||||
* {@link angular.markup Markup} - How to use markup to create shorthand for a widget or a
|
||||
directive. For example, markup is what allows you to use the double curly brace notation
|
||||
`{{}}` to bind expressions to elements.
|
||||
* {@link guide.data-binding Data Binding} - About the mechanism that keeps the model the single
|
||||
source of truth of your application at all times, with the view as a live projection of the
|
||||
model.
|
||||
* {@link angular.filter Filter} - How to format your data for display to the user.
|
||||
* {@link angular.widget Widget} - How to create new DOM elements that the browser doesn't already
|
||||
understand.
|
||||
* {@link angular.validator Validator} - How to validate user input.
|
||||
* {@link angular.formatter Formatter} - How to format stored data to user-readable text and
|
||||
parse the text back to the stored form.
|
||||
* {@link guide.css CSS} - Built-in CSS classes, when angular assigns them, and how to override
|
||||
their styles.
|
||||
* {@link angular.scope Scope} - The model in the model-view-controller design pattern. You can
|
||||
think about scopes as the JavaScript objects that have extra APIs for registering watchers.
|
||||
* {@link guide.expression Expression} - The bindings that are embedded in an angular View.
|
||||
* {@link angular.service Service} - Objects that are wired through dependency injection and then
|
||||
injected into the root scope.
|
||||
* {@link guide.testing Testing}
|
||||
* service:$browser(mock)
|
||||
* {@link guide.downloading Downloading} - How to download, compile, and host the angular
|
||||
environment on your own server.
|
||||
166
docs/guide.overview.ngdoc
Normal file
166
docs/guide.overview.ngdoc
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Overview
|
||||
@description
|
||||
|
||||
# What is angular?
|
||||
Angular teaches your old browser new tricks. It is what HTML would have been if it had been
|
||||
designed for building web applications.
|
||||
|
||||
Take a simple example of user input as shown below. If you were using just HTML and JavaScript to
|
||||
implement this form, you would need to define listeners, DOM updates, and complex input validators
|
||||
in order to update and format the result. In angular you can achieve the effect with zero lines
|
||||
of JavaScript code using a declarative approach. Click on the source tab of the example below to
|
||||
view the angular implementation of this form.
|
||||
|
||||
<doc:example>
|
||||
<doc:source>
|
||||
QTY: <input name="qty" value="1" ng:validate="integer:0" ng:required/>
|
||||
*
|
||||
Cost: <input name="cost" value="19.95" ng:validate="number" ng:required/>
|
||||
=
|
||||
{{qty * cost | currency}}
|
||||
</doc:source>
|
||||
<doc:scenario>
|
||||
it('should show of angular binding', function(){
|
||||
expect(binding('qty * cost')).toEqual('$19.95');
|
||||
input('qty').enter('2');
|
||||
input('cost').enter('5.00');
|
||||
expect(binding('qty * cost')).toEqual('$10.00');
|
||||
});
|
||||
</doc:scenario>
|
||||
</doc:example>
|
||||
|
||||
Angular is to AJAX apps as Ruby on Rails is to round trip apps.
|
||||
|
||||
# Angular frees you from:
|
||||
* **Registering callbacks:** Registering callbacks clutters your code, and it makes it hard to see
|
||||
the forest from the trees. Removing common boilerplate code such as callbacks is advantageous
|
||||
because it leaves the JavaScript with a more succinct version of your code, better describing
|
||||
what your application does.
|
||||
* **Manipulating HTML DOM programatically:** Manipulating HTML DOM is a cornerstone of AJAX
|
||||
applications, but it is very cumbersome and error-prone. By declaratively describing how the UI
|
||||
should change as your application state changes, you are freed from low level DOM manipulation
|
||||
activities. Most applications written with angular never have to programatically manipulate
|
||||
the DOM.
|
||||
* **Marshaling data to and from the UI:** CRUD operations make up the majority of most AJAX
|
||||
applications. The flow of marshaling data from the server to an internal object to a HTML form,
|
||||
validating the form, displaying validation errors, returning to an internal model and then back
|
||||
to the server creates a lot of boilerplate code. angular eliminates almost all of this
|
||||
boilerplate. leaving code that is richer and describes the overall flow of the application
|
||||
rather than implementation details.
|
||||
* **Writing tons of initialization code just to get started:** Typically you need to write a lot
|
||||
of plumbing and initialization code just to get a basic "Hello World" AJAX app working. With
|
||||
angular you can bootstrap your app easily using services, which are auto-injected into your
|
||||
application in a GUICE-like dependency-injection style. This allows you to get started
|
||||
developing features quickly. As a bonus, you get full control over the initialization process
|
||||
in automated tests.
|
||||
|
||||
|
||||
# angular is/has:
|
||||
* **An HTML Compiler:** angular is an HTML compiler in the browser. It allows you to give meaning
|
||||
to any HTML element, attribute, or text and create new primitives as building blocks for your
|
||||
application.
|
||||
* **Declarative:** Declarative means that you describe what the page looks like rather than
|
||||
instructing how to draw the page. HTML is great at declaring static documents. Angular extends
|
||||
the declarative nature of HTML beyond static documents to define dynamic applications.
|
||||
* **Declarative Templates:** In angular, you write HTML to declare the view and UI templates for
|
||||
your application. You can express many common application constructs without using any
|
||||
JavaScript at all.
|
||||
* **Bidirectional Data Binding:** Allows your application to have a single source of truth
|
||||
(your model), where the HTML is a projection of the internal state of your application, which
|
||||
you can provide to the user in a declarative way.
|
||||
* **Built-in Services:** angular provides many standard AJAX operations to get you going quickly,
|
||||
and dependency-injection allows you to swap them out as needed. Common services include:
|
||||
Dependency Inject, History Management, URL Router, AJAX/XHR requests, and data caching,
|
||||
to name a few.
|
||||
* **Very testable:** Testing difficulty is dramatically affected by the way you structure your
|
||||
code. With angular, testability is baked in.
|
||||
|
||||
# angular is NOT a:
|
||||
* **Library:** You don't call its functions.
|
||||
* **Framework:** It does not call your functions.
|
||||
* **DOM Manipulation Library:** It does not provide a way to manipulate DOM, but does provide
|
||||
primitives to create UI projections of your data.
|
||||
* **Widget Library:** There are lots of existing widget libraries that you can integrate with
|
||||
angular.
|
||||
|
||||
|
||||
|
||||
# Not just another templating system
|
||||
|
||||
At the highest level, angular looks like a just another templating system, but there are few
|
||||
important reasons why angular is different and makes it a very good fit for application
|
||||
development.
|
||||
|
||||
Angular:
|
||||
* **Uses HTML/CSS syntax:** This makes it easy to read and can be edited with existing HTML/CSS
|
||||
authoring tools.
|
||||
* **Extends HTML vocabulary:** Angular allows you to create new HTML tags, which expand into
|
||||
dynamic UI components.
|
||||
* **Executes in the browser:** Removes the round trip to the server for many operations and
|
||||
creates instant feedback for users.
|
||||
* **Bidirectional data binding:** The model is the single source of truth. Programmatic changes
|
||||
to the model are automatically reflected in the view. Any changes by the user to the view are
|
||||
automatically reflected in the model.
|
||||
* **Services:** These allow for a reusable way of injecting dependencies into an application.
|
||||
* **MVC:** Clean separation between model-view-controller, which aids in understanding,
|
||||
maintenance, and testing of large systems.
|
||||
|
||||
|
||||
# The angular philosophy
|
||||
|
||||
Angular is built around the belief that declarative code is preferred over imperative when it
|
||||
comes to building UIs and connecting the pieces together.
|
||||
|
||||
As an example, if you wanted to add a new label to your application, you could do so by simply
|
||||
adding text to the HTML template, saving the code, and refreshing your browser:
|
||||
|
||||
<pre>
|
||||
<span class="label">Hello</span>
|
||||
</pre>
|
||||
|
||||
In programmatic systems you would have to write and run code like this:
|
||||
|
||||
<pre>
|
||||
var label = new Label();
|
||||
label.setText('Hello');
|
||||
label.setClass('label');
|
||||
parent.addChild(label);
|
||||
</pre>
|
||||
|
||||
## Benefits:
|
||||
|
||||
* Compile-free: Change your template and logic code and reload the browser to see it run
|
||||
immediately. In contrast, programmatic serverside views often need to be compiled and executed
|
||||
to be viewed, which takes time. This dramatically increases the speed of your development cycle.
|
||||
* Declarative templates are easier to understand and change than programmatic instructions.
|
||||
* Declarative templates can be edited in existing HTML editors such as DreamWeaver, Eclipse,
|
||||
TextMate, Vim, etc.
|
||||
* Declarative templates can be edited by web designers without the need to work with web
|
||||
developers.
|
||||
|
||||
HTML is missing certain features, which angular adds via its compiler, thereby "teaching" the
|
||||
browser these new tricks:
|
||||
|
||||
* Dynamic behavior
|
||||
* Componentizing HTML snippets into reusable components
|
||||
* Dynamically include other HTML templates
|
||||
* Two-way data binding
|
||||
* Rich validation in forms
|
||||
* Model-View-Controller modularization
|
||||
|
||||
# Watch a presentation about angular
|
||||
|
||||
<object width="480" height="385">
|
||||
<param name="movie" value="http://www.youtube.com/v/elvcgVSynRg&hl=en_US&fs=1"></param>
|
||||
<param name="allowFullScreen" value="true"></param>
|
||||
<param name="allowscriptaccess" value="always"></param>
|
||||
<embed src="http://www.youtube.com/v/elvcgVSynRg&hl=en_US&fs=1"
|
||||
type="application/x-shockwave-flash" allowscriptaccess="always"
|
||||
allowfullscreen="true" width="480" height="385"></embed>
|
||||
</object>
|
||||
|
||||
{@link https://docs.google.com/present/edit?id=0Abz6S2TvsDWSZDQ0OWdjaF8yNTRnODczazdmZg&hl=en&authkey=CO-b7oID Presentation}
|
||||
|
|
||||
{@link https://docs.google.com/document/edit?id=1ZHVhqC0apbzPRQcgnb1Ye-bAUbNJ-IlFMyPBPCZ2cYU&hl=en&authkey=CInnwLYO Source}
|
||||
22
docs/guide.template.ngdoc
Normal file
22
docs/guide.template.ngdoc
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
@workInProgress
|
||||
@ngdoc overview
|
||||
@name Developer Guide: Template
|
||||
@description
|
||||
#Template
|
||||
|
||||
You can think of a template in angular as a domain-specific language that you can use to easily
|
||||
build the view of your web application. You create a template by writing HTML and CSS, and you can
|
||||
add any constructs that you want to the HTML. This means that you can attach rendering and behavior
|
||||
to any HTML element, attribute or markup text.
|
||||
|
||||
In addition to writing HTML and CSS, you can also use the following angular constructs to create
|
||||
your template:
|
||||
|
||||
* **Directive** - XML attributes that augment an existing DOM element.
|
||||
* **Markup** - Lets you create shorthand for a widget or a directive. For example, markup is what
|
||||
allows you to use the double curly brace notation {{}} to bind expressions to
|
||||
elements.
|
||||
* **Filter** - Lets you format your data for display to the user.
|
||||
* **Widget** - Lets you create new DOM elements that the browser doesn't already understand.
|
||||
* **Validator** - Lets you validate user input.
|
||||
* **Formatter** - Lets you format the input object into a user readable view.
|
||||
BIN
docs/img/One_Way_Data_Binding.png
Normal file
BIN
docs/img/One_Way_Data_Binding.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
docs/img/Two_Way_Data_Binding.png
Normal file
BIN
docs/img/Two_Way_Data_Binding.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 49 KiB |
|
|
@ -1,9 +1,14 @@
|
|||
var DOM = require('dom.js').DOM;
|
||||
|
||||
describe('dom', function(){
|
||||
var dom;
|
||||
|
||||
beforeEach(function(){
|
||||
dom = new DOM();
|
||||
});
|
||||
|
||||
describe('example', function(){
|
||||
it('should render code, live, test', function(){
|
||||
var dom = new DOM();
|
||||
dom.example('desc', 'src', 'scenario');
|
||||
expect(dom.toString()).toEqual(
|
||||
'<h1>Example</h1>\n' +
|
||||
|
|
@ -15,7 +20,6 @@ describe('dom', function(){
|
|||
});
|
||||
|
||||
it('should render non-live, test with description', function(){
|
||||
var dom = new DOM();
|
||||
dom.example('desc', 'src', false);
|
||||
expect(dom.toString()).toEqual('<h1>Example</h1>\n' +
|
||||
'<div class="example">' +
|
||||
|
|
@ -26,10 +30,32 @@ describe('dom', function(){
|
|||
});
|
||||
|
||||
it('should render non-live, test', function(){
|
||||
var dom = new DOM();
|
||||
dom.example('desc', 'src', false);
|
||||
expect(dom.toString()).toContain('<pre class="brush: js; html-script: true;">src</pre>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('h', function(){
|
||||
|
||||
it('should render using function', function(){
|
||||
var cbThis;
|
||||
var cdValue;
|
||||
dom.h('heading', 'content', function(value){
|
||||
cbThis = this;
|
||||
cbValue = value;
|
||||
});
|
||||
expect(cbThis).toEqual(dom);
|
||||
expect(cbValue).toEqual('content');
|
||||
});
|
||||
|
||||
it('should update heading numbers', function(){
|
||||
dom.h('heading', function(){
|
||||
this.html('<h1>sub-heading</h1>');
|
||||
});
|
||||
expect(dom.toString()).toContain('<h1>heading</h1>');
|
||||
expect(dom.toString()).toContain('<h2>sub-heading</h2>');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
|||
|
|
@ -19,9 +19,28 @@ describe('ngdoc', function(){
|
|||
describe('metadata', function(){
|
||||
|
||||
it('should find keywords', function(){
|
||||
expect(new Doc('\nHello: World! @ignore.').keywords()).toEqual('hello world');
|
||||
expect(new Doc('\nHello: World! @ignore. $abc').keywords()).toEqual('$abc hello world');
|
||||
expect(new Doc('The `ng:class-odd` and').keywords()).toEqual('and ng:class-odd the');
|
||||
});
|
||||
|
||||
it('should have shortName', function(){
|
||||
var d1 = new Doc('@name a.b.c').parse();
|
||||
var d2 = new Doc('@name a.b.ng:c').parse();
|
||||
var d3 = new Doc('@name some text: more text').parse();
|
||||
expect(ngdoc.metadata([d1])[0].shortName).toEqual('c');
|
||||
expect(ngdoc.metadata([d2])[0].shortName).toEqual('ng:c');
|
||||
expect(ngdoc.metadata([d3])[0].shortName).toEqual('more text');
|
||||
});
|
||||
|
||||
it('should have depth information', function(){
|
||||
var d1 = new Doc('@name a.b.c').parse();
|
||||
var d2 = new Doc('@name a.b.ng:c').parse();
|
||||
var d3 = new Doc('@name some text: more text').parse();
|
||||
expect(ngdoc.metadata([d1])[0].depth).toEqual(2);
|
||||
expect(ngdoc.metadata([d2])[0].depth).toEqual(2);
|
||||
expect(ngdoc.metadata([d3])[0].depth).toEqual(1);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('parse', function(){
|
||||
|
|
@ -61,9 +80,68 @@ describe('ngdoc', function(){
|
|||
expect(doc.example).toEqual('A\n\nB');
|
||||
});
|
||||
|
||||
it('should parse filename', function(){
|
||||
var doc = new Doc('@name friendly name', 'docs/a.b.ngdoc', 1);
|
||||
doc.parse(0);
|
||||
expect(doc.id).toEqual('a.b');
|
||||
expect(doc.name).toEqual('friendly name');
|
||||
});
|
||||
|
||||
it('should escape <doc:source> element', function(){
|
||||
var doc = new Doc('@description before <doc:example>' +
|
||||
'<doc:source>\n<>\n</doc:source></doc:example> after');
|
||||
doc.parse();
|
||||
expect(doc.description).toContain('<p>before </p><doc:example>' +
|
||||
'<doc:source>\n<>\n</doc:source></doc:example><p>after</p>');
|
||||
});
|
||||
|
||||
it('should escape <doc:scenario> element', function(){
|
||||
var doc = new Doc('@description before <doc:example>' +
|
||||
'<doc:scenario>\n<>\n</doc:scenario></doc:example> after');
|
||||
doc.parse();
|
||||
expect(doc.description).toContain('<p>before </p><doc:example>' +
|
||||
'<doc:scenario>\n<>\n</doc:scenario></doc:example><p>after</p>');
|
||||
});
|
||||
|
||||
describe('sorting', function(){
|
||||
function property(name) {
|
||||
return function(obj) {return obj[name];};
|
||||
}
|
||||
function noop(){}
|
||||
function doc(type, name){
|
||||
return {
|
||||
id: name,
|
||||
ngdoc: type,
|
||||
keywords: noop
|
||||
};
|
||||
}
|
||||
|
||||
var angular_widget = doc('overview', 'angular.widget');
|
||||
var angular_x = doc('function', 'angular.x');
|
||||
var angular_y = doc('property', 'angular.y');
|
||||
|
||||
it('should put angular.fn() in front of angular.widget, etc', function(){
|
||||
expect(ngdoc.metadata([angular_widget, angular_y, angular_x]).map(property('id')))
|
||||
.toEqual(['angular.x', 'angular.y', 'angular.widget' ]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('scenario', function(){
|
||||
it('should render from @example/@scenario and <doc:example>', function(){
|
||||
var doc = new Doc(
|
||||
'@id id\n' +
|
||||
'@description <doc:example><doc:scenario>scenario0</doc:scenario></doc:example>' +
|
||||
'@example exempleText\n' +
|
||||
'@scenario scenario1\n' +
|
||||
'@scenario scenario2').parse();
|
||||
expect(ngdoc.scenarios([doc])).toContain('describe("id"');
|
||||
expect(ngdoc.scenarios([doc])).toContain('navigateTo("index.html#!id")');
|
||||
expect(ngdoc.scenarios([doc])).toContain('\n scenario0\n');
|
||||
expect(ngdoc.scenarios([doc])).toContain('\n scenario1\n');
|
||||
expect(ngdoc.scenarios([doc])).toContain('\n scenario2\n');
|
||||
});
|
||||
});
|
||||
|
||||
describe('markdown', function(){
|
||||
|
|
@ -86,8 +164,9 @@ describe('ngdoc', function(){
|
|||
|
||||
it('should replace text between two <pre></pre> tags', function() {
|
||||
expect(markdown('<pre>x</pre># One<pre>b</pre>')).
|
||||
toMatch('</div><h3>One</h3><div');
|
||||
toMatch('</div><h1>One</h1><div');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('trim', function(){
|
||||
|
|
@ -230,7 +309,7 @@ describe('ngdoc', function(){
|
|||
expect(doc.description).
|
||||
toBe('<p>foo </p>' +
|
||||
'<div ng:non-bindable><pre class="brush: js; html-script: true;">abc</pre></div>' +
|
||||
'<h3>bah</h3>\n\n' +
|
||||
'<h1>bah</h1>\n\n' +
|
||||
'<p>foo </p>' +
|
||||
'<div ng:non-bindable><pre class="brush: js; html-script: true;">cba</pre></div>');
|
||||
|
||||
|
|
@ -243,18 +322,15 @@ describe('ngdoc', function(){
|
|||
'{@link angular.directive.ng:foo ng:foo}');
|
||||
doc.parse();
|
||||
expect(doc.description).
|
||||
toBe('<p>foo <a href="#!angular.foo"><code>angular.foo</code></a></p>\n\n' +
|
||||
'<p>da <a href="#!angular.foo"><code>bar foo bar</code></a> </p>\n\n' +
|
||||
'<p>dad<a href="#!angular.foo"><code>angular.foo</code></a></p>\n\n' +
|
||||
'<p><a href="#!angular.directive.ng:foo"><code>ng:foo</code></a></p>');
|
||||
toContain('foo <a href="#!angular.foo"><code>angular.foo</code></a>');
|
||||
expect(doc.description).
|
||||
toContain('da <a href="#!angular.foo"><code>bar foo bar</code></a>');
|
||||
expect(doc.description).
|
||||
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>');
|
||||
});
|
||||
|
||||
it('should increment all headings by two', function() {
|
||||
var doc = new Doc('@description # foo\nabc\n## bar \n xyz');
|
||||
doc.parse();
|
||||
expect(doc.description).
|
||||
toBe('<h3>foo</h3>\n\n<p>abc</p>\n\n<h4>bar</h4>\n\n<p>xyz</p>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('@example', function(){
|
||||
|
|
@ -291,8 +367,8 @@ describe('ngdoc', function(){
|
|||
|
||||
});
|
||||
|
||||
describe('@deprecated', function() {
|
||||
it('should parse @deprecated', function() {
|
||||
describe('@depricated', function() {
|
||||
it('should parse @depricated', function() {
|
||||
var doc = new Doc('@deprecated Replaced with foo.');
|
||||
doc.parse();
|
||||
expect(doc.deprecated).toBe('Replaced with foo.');
|
||||
|
|
@ -315,6 +391,17 @@ describe('ngdoc', function(){
|
|||
});
|
||||
|
||||
describe('usage', function(){
|
||||
describe('overview', function(){
|
||||
it('should supress description heading', function(){
|
||||
var doc = new Doc('@ngdoc overview\n@name angular\n@description\n#heading\ntext');
|
||||
doc.parse();
|
||||
expect(doc.html()).toContain('text');
|
||||
expect(doc.html()).toContain('<h2>heading</h2>');
|
||||
expect(doc.html()).not.toContain('Description');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('filter', function(){
|
||||
it('should format', function(){
|
||||
var doc = new Doc({
|
||||
|
|
|
|||
|
|
@ -3,12 +3,18 @@
|
|||
*/
|
||||
|
||||
exports.DOM = DOM;
|
||||
exports.htmlEscape = htmlEscape;
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
function htmlEscape(text){
|
||||
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
|
||||
function DOM(){
|
||||
this.out = [];
|
||||
this.headingDepth = 1;
|
||||
this.headingDepth = 0;
|
||||
}
|
||||
|
||||
var INLINE_TAGS = {
|
||||
|
|
@ -23,7 +29,7 @@ DOM.prototype = {
|
|||
|
||||
text: function(content) {
|
||||
if (typeof content == "string") {
|
||||
this.out.push(content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'));
|
||||
this.out.push(htmlEscape(content));
|
||||
} else if (typeof content == 'function') {
|
||||
content.call(this, this);
|
||||
} else if (content instanceof Array) {
|
||||
|
|
@ -33,6 +39,13 @@ DOM.prototype = {
|
|||
|
||||
html: function(html) {
|
||||
if (html) {
|
||||
var headingDepth = this.headingDepth;
|
||||
for ( var i = 10; i > 0; --i) {
|
||||
html = html
|
||||
.replace(new RegExp('(<\/?h)' + i + '(>)', 'gm'), function(all, start, end){
|
||||
return start + (i + headingDepth) + end;
|
||||
});
|
||||
}
|
||||
this.out.push(html);
|
||||
}
|
||||
},
|
||||
|
|
@ -80,15 +93,17 @@ DOM.prototype = {
|
|||
|
||||
h: function(heading, content, fn){
|
||||
if (content==undefined || content && content.legth == 0) return;
|
||||
this.tag('h' + this.headingDepth, heading);
|
||||
this.headingDepth++;
|
||||
this.tag('h' + this.headingDepth, heading);
|
||||
var className = typeof heading == 'string'
|
||||
? {'class': heading.toLowerCase().replace(/[^\d\w_]/, '-')}
|
||||
? {'class': heading.toLowerCase().replace(/[^\d\w_]/mg, '-').replace(/-+/gm, '-')}
|
||||
: null;
|
||||
if (content instanceof Array) {
|
||||
this.ul(content, className, fn);
|
||||
} else if (fn) {
|
||||
this.tag('div', className, fn);
|
||||
this.tag('div', className, function(){
|
||||
fn.call(this, content);
|
||||
});
|
||||
} else {
|
||||
this.tag('div', className, content);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,10 +20,11 @@ var work = callback.chain(function(){
|
|||
var writes = callback.chain(function(){
|
||||
ngdoc.merge(docs);
|
||||
docs.forEach(function(doc){
|
||||
writer.output(doc.name + '.html', doc.html(), writes.waitFor());
|
||||
writer.output(doc.id + '.html', doc.html(), writes.waitFor());
|
||||
});
|
||||
var metadata = ngdoc.metadata(docs);
|
||||
writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata), ';'], writes.waitFor());
|
||||
writer.output('docs-keywords.js', ['NG_PAGES=', JSON.stringify(metadata).replace(/{/g, '\n{'), ';'], writes.waitFor());
|
||||
writer.copyImages(writes.waitFor());
|
||||
writer.copy('index.html', writes.waitFor());
|
||||
writer.copy('docs.js', writes.waitFor());
|
||||
writer.copy('docs.css', writes.waitFor());
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
var Showdown = require('showdown').Showdown;
|
||||
var DOM = require('dom.js').DOM;
|
||||
var htmlEscape = require('dom.js').htmlEscape;
|
||||
var NEW_LINE = /\n\r?/;
|
||||
|
||||
exports.markdown = markdown;
|
||||
|
|
@ -39,7 +40,7 @@ Doc.prototype = {
|
|||
var words = [];
|
||||
var tokens = this.text.toLowerCase().split(/[,\.\`\'\"\s]+/mg);
|
||||
tokens.forEach(function(key){
|
||||
var match = key.match(/^(([a-z]|ng\:)[\w\_\-]{2,})/);
|
||||
var match = key.match(/^(([\$\_a-z]|ng\:)[\w\_\-]{2,})/);
|
||||
if (match){
|
||||
key = match[1];
|
||||
if (!keywords[key]) {
|
||||
|
|
@ -57,6 +58,11 @@ Doc.prototype = {
|
|||
var atText;
|
||||
var match;
|
||||
var self = this;
|
||||
this.scenarios = [];
|
||||
this.requires = [];
|
||||
this.param = [];
|
||||
this.properties = [];
|
||||
this.methods = [];
|
||||
self.text.split(NEW_LINE).forEach(function(line){
|
||||
if (match = line.match(/^\s*@(\w+)(\s+(.*))?/)) {
|
||||
// we found @name ...
|
||||
|
|
@ -73,6 +79,9 @@ Doc.prototype = {
|
|||
});
|
||||
flush();
|
||||
this.shortName = (this.name || '').split(/[\.#]/).pop();
|
||||
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.name; // default to name
|
||||
this.description = markdown(this.description);
|
||||
this['this'] = markdown(this['this']);
|
||||
this.exampleDescription = markdown(this.exampleDescription || this.exampleDesc);
|
||||
|
|
@ -94,7 +103,6 @@ Doc.prototype = {
|
|||
optional: !!match[2],
|
||||
'default':match[6]
|
||||
};
|
||||
self.param = self.param || [];
|
||||
self.param.push(param);
|
||||
} else if (atName == 'returns') {
|
||||
var match = text.match(/^{([^}=]+)}\s+(.*)/);
|
||||
|
|
@ -105,9 +113,16 @@ Doc.prototype = {
|
|||
type: match[1],
|
||||
description: markdown(text.replace(match[0], match[2]))
|
||||
};
|
||||
} else if(atName == 'description') {
|
||||
text.replace(/<doc:scenario>([\s\S]*)<\/doc:scenario>/mi,
|
||||
function(_, scenario){
|
||||
self.scenarios.push(scenario);
|
||||
});
|
||||
self.description = text;
|
||||
} else if(atName == 'requires') {
|
||||
self.requires = self.requires || [];
|
||||
self.requires.push(text);
|
||||
} else if(atName == 'scenario') {
|
||||
self.scenarios.push(text);
|
||||
} else if(atName == 'property') {
|
||||
var match = text.match(/^({(\S+)}\s*)?(\S+)(\s+(.*))?/);
|
||||
if (!match) {
|
||||
|
|
@ -118,7 +133,6 @@ Doc.prototype = {
|
|||
name: match[3],
|
||||
description: match[5] || ''
|
||||
};
|
||||
self.properties = self.properties || [];
|
||||
self.properties.push(property);
|
||||
} else {
|
||||
self[atName] = text;
|
||||
|
|
@ -135,25 +149,10 @@ Doc.prototype = {
|
|||
notice('workInProgress', 'Work in Progress',
|
||||
'This page is currently being revised. It might be incomplete or contain inaccuracies.');
|
||||
notice('deprecated', 'Deprecated API', self.deprecated);
|
||||
dom.h('Description', self.description, html);
|
||||
dom.h('Dependencies', self.requires);
|
||||
|
||||
usage();
|
||||
|
||||
dom.h('Methods', self.methods, function(method){
|
||||
var signature = (method.param || []).map(property('name'));
|
||||
dom.h(method.shortName + '(' + signature.join(', ') + ')', method, function(){
|
||||
dom.html(method.description);
|
||||
method.html_usage_parameters(dom);
|
||||
dom.example(method.exampleDescription, method.example, false);
|
||||
});
|
||||
});
|
||||
dom.h('Properties', self.properties, function(property){
|
||||
dom.h(property.name, function(){
|
||||
dom.text(property.description);
|
||||
dom.example(property.exampleDescription, property.example, false);
|
||||
});
|
||||
});
|
||||
(self['html_usage_' + self.ngdoc] || function(){
|
||||
throw new Error("Don't know how to format @ngdoc: " + self.ngdoc);
|
||||
}).call(self, dom);
|
||||
|
||||
dom.example(self.exampleDescription, self.example, self.scenario);
|
||||
});
|
||||
|
|
@ -162,29 +161,6 @@ Doc.prototype = {
|
|||
|
||||
//////////////////////////
|
||||
|
||||
function html(text){
|
||||
this.html(text);
|
||||
}
|
||||
|
||||
function usage(){
|
||||
(self['html_usage_' + self.ngdoc] || function(){
|
||||
throw new Error("Don't know how to format @ngdoc: " + self.ngdoc);
|
||||
}).call(self, dom);
|
||||
}
|
||||
|
||||
function section(name, property, fn) {
|
||||
var value = self[property];
|
||||
if (value) {
|
||||
dom.h2(name);
|
||||
if (typeof value == 'string') {
|
||||
value = markdown(value) + '\n';
|
||||
fn ? fn(value) : dom.html(value);
|
||||
} else if (value instanceof Array) {
|
||||
dom.ul(value, fn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function notice(name, legend, msg){
|
||||
if (self[name] == undefined) return;
|
||||
dom.tag('fieldset', {'class':name}, function(dom){
|
||||
|
|
@ -240,6 +216,8 @@ Doc.prototype = {
|
|||
|
||||
html_usage_function: function(dom){
|
||||
var self = this;
|
||||
dom.h('Description', self.description, dom.html);
|
||||
dom.h('Dependencies', self.requires);
|
||||
dom.h('Usage', function(){
|
||||
dom.code(function(){
|
||||
dom.text(self.name);
|
||||
|
|
@ -256,11 +234,13 @@ Doc.prototype = {
|
|||
|
||||
html_usage_directive: function(dom){
|
||||
var self = this;
|
||||
dom.h('Description', self.description, dom.html);
|
||||
dom.h('Dependencies', self.requires);
|
||||
dom.h('Usage', function(){
|
||||
dom.tag('pre', {'class':"brush: js; html-script: true;"}, function(){
|
||||
dom.text('<' + self.element + ' ');
|
||||
dom.text(self.shortName);
|
||||
if (self.param) {
|
||||
if (self.param.length) {
|
||||
dom.text('="' + self.param[0].name + '"');
|
||||
}
|
||||
dom.text('>\n ...\n');
|
||||
|
|
@ -272,6 +252,8 @@ Doc.prototype = {
|
|||
|
||||
html_usage_filter: function(dom){
|
||||
var self = this;
|
||||
dom.h('Description', self.description, dom.html);
|
||||
dom.h('Dependencies', self.requires);
|
||||
dom.h('Usage', function(){
|
||||
dom.h('In HTML Template Binding', function(){
|
||||
dom.tag('code', function(){
|
||||
|
|
@ -302,6 +284,8 @@ Doc.prototype = {
|
|||
|
||||
html_usage_formatter: function(dom){
|
||||
var self = this;
|
||||
dom.h('Description', self.description, dom.html);
|
||||
dom.h('Dependencies', self.requires);
|
||||
dom.h('Usage', function(){
|
||||
dom.h('In HTML Template Binding', function(){
|
||||
dom.code(function(){
|
||||
|
|
@ -340,6 +324,8 @@ Doc.prototype = {
|
|||
|
||||
html_usage_validator: function(dom){
|
||||
var self = this;
|
||||
dom.h('Description', self.description, dom.html);
|
||||
dom.h('Dependencies', self.requires);
|
||||
dom.h('Usage', function(){
|
||||
dom.h('In HTML Template Binding', function(){
|
||||
dom.code(function(){
|
||||
|
|
@ -368,6 +354,8 @@ Doc.prototype = {
|
|||
|
||||
html_usage_widget: function(dom){
|
||||
var self = this;
|
||||
dom.h('Description', self.description, dom.html);
|
||||
dom.h('Dependencies', self.requires);
|
||||
dom.h('Usage', function(){
|
||||
dom.h('In HTML Template Binding', function(){
|
||||
dom.code(function(){
|
||||
|
|
@ -376,7 +364,7 @@ Doc.prototype = {
|
|||
dom.text(self.element);
|
||||
dom.text(' ');
|
||||
dom.text(self.shortName.substring(1));
|
||||
if (self.param) {
|
||||
if (self.param.length) {
|
||||
dom.text('="');
|
||||
dom.text(self.param[0].name);
|
||||
dom.text('"');
|
||||
|
|
@ -407,9 +395,27 @@ Doc.prototype = {
|
|||
},
|
||||
|
||||
html_usage_overview: function(dom){
|
||||
dom.html(this.description);
|
||||
},
|
||||
|
||||
html_usage_service: function(dom){
|
||||
dom.h('Description', this.description, dom.html);
|
||||
dom.h('Dependencies', this.requires);
|
||||
|
||||
dom.h('Methods', this.methods, function(method){
|
||||
var signature = (method.param || []).map(property('name'));
|
||||
dom.h(method.shortName + '(' + signature.join(', ') + ')', method, function(){
|
||||
dom.html(method.description);
|
||||
method.html_usage_parameters(dom);
|
||||
dom.example(method.exampleDescription, method.example, false);
|
||||
});
|
||||
});
|
||||
dom.h('Properties', this.properties, function(property){
|
||||
dom.h(property.name, function(){
|
||||
dom.text(property.description);
|
||||
dom.example(property.exampleDescription, property.example, false);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
parameters: function(dom, separator, skipFirst, prefix) {
|
||||
|
|
@ -433,7 +439,7 @@ Doc.prototype = {
|
|||
//////////////////////////////////////////////////////////
|
||||
function markdown (text) {
|
||||
if (!text) return text;
|
||||
var parts = text.split(/(<pre>[\s\S]*?<\/pre>)/),
|
||||
var parts = text.split(/(<pre>[\s\S]*?<\/pre>|<doc:example>[\s\S]*?<\/doc:example>)/),
|
||||
match;
|
||||
|
||||
parts.forEach(function(text, i){
|
||||
|
|
@ -443,39 +449,51 @@ function markdown (text) {
|
|||
content.replace(/</g, '<').replace(/>/g, '>') +
|
||||
'</pre></div>';
|
||||
});
|
||||
} else if (text.match(/^<doc:example>/)) {
|
||||
text = text.replace(/(<doc:source>)([\s\S]*)(<\/doc:source>)/mi,
|
||||
function(_, before, content, after){
|
||||
return before + htmlEscape(content) + after;
|
||||
});
|
||||
text = text.replace(/(<doc:scenario>)([\s\S]*)(<\/doc:scenario>)/mi,
|
||||
function(_, before, content, after){
|
||||
return before + htmlEscape(content) + after;
|
||||
});
|
||||
} else {
|
||||
text = text.replace(/<angular\/>/gm, '<tt><angular/></tt>');
|
||||
text = new Showdown.converter().makeHtml(text.replace(/^#/gm, '###'));
|
||||
|
||||
while (match = text.match(R_LINK)) {
|
||||
text = text.replace(match[0], '<a href="#!' + match[1] + '"><code>' +
|
||||
(match[4] || match[1]) +
|
||||
'</code></a>');
|
||||
}
|
||||
text = text.replace(/{@link ([^\s}]+)((\s|\n)+(.+?))?\s*}/gm,
|
||||
function(_all, url, _2, _3, title){
|
||||
return '<a href="#!' + url + '">'
|
||||
+ (url.match(/^angular\./) ? '<code>' : '')
|
||||
+ (title || url)
|
||||
+ (url.match(/^angular\./) ? '</code>' : '')
|
||||
+ '</a>';
|
||||
});
|
||||
text = new Showdown.converter().makeHtml(text);
|
||||
}
|
||||
parts[i] = text;
|
||||
});
|
||||
return parts.join('');
|
||||
};
|
||||
var R_LINK = /{@link ([^\s}]+)((\s|\n)+(.+?))?\s*}/m;
|
||||
// 1 123 3 4 42
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
function scenarios(docs){
|
||||
var specs = [];
|
||||
docs.forEach(function(doc){
|
||||
specs.push('describe("' + doc.id + '", function(){');
|
||||
specs.push(' beforeEach(function(){');
|
||||
specs.push(' browser().navigateTo("index.html#!' + doc.id + '");');
|
||||
specs.push(' });');
|
||||
specs.push('');
|
||||
doc.scenarios.forEach(function(scenario){
|
||||
specs.push(trim(scenario, ' '));
|
||||
specs.push('');
|
||||
});
|
||||
specs.push('});');
|
||||
specs.push('');
|
||||
if (doc.scenario) {
|
||||
specs.push('describe("');
|
||||
specs.push(doc.name);
|
||||
specs.push('", function(){\n');
|
||||
specs.push(' beforeEach(function(){\n');
|
||||
specs.push(' browser().navigateTo("index.html#!' + doc.name + '");');
|
||||
specs.push(' });\n\n');
|
||||
specs.push(doc.scenario);
|
||||
specs.push('\n});\n\n');
|
||||
}
|
||||
});
|
||||
return specs;
|
||||
return specs.join('\n');
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -483,8 +501,17 @@ function scenarios(docs){
|
|||
function metadata(docs){
|
||||
var words = [];
|
||||
docs.forEach(function(doc){
|
||||
var path = (doc.name || '').split(/(\.|\:\s+)/);
|
||||
for ( var i = 1; i < path.length; i++) {
|
||||
path.splice(i, 1);
|
||||
}
|
||||
var depth = path.length - 1;
|
||||
var shortName = path.pop();
|
||||
words.push({
|
||||
name:doc.name,
|
||||
id: doc.id,
|
||||
name: doc.name,
|
||||
depth: depth,
|
||||
shortName: shortName,
|
||||
type: doc.ngdoc,
|
||||
keywords:doc.keywords()
|
||||
});
|
||||
|
|
@ -493,37 +520,50 @@ function metadata(docs){
|
|||
return words;
|
||||
}
|
||||
|
||||
function keywordSort(a,b){
|
||||
// supper ugly comparator that orders all utility methods and objects before all the other stuff
|
||||
// like widgets, directives, services, etc.
|
||||
// Mother of all beautiful code please forgive me for the sin that this code certainly is.
|
||||
|
||||
if (a.name === b.name) return 0;
|
||||
if (a.name === 'angular') return -1;
|
||||
if (b.name === 'angular') return 1;
|
||||
|
||||
function namespacedName(page) {
|
||||
return (page.name.match(/\./g).length === 1 && page.type !== 'overview' ? '0' : '1') + page.name;
|
||||
var KEYWORD_PRIORITY = {
|
||||
'.guide': 1,
|
||||
'.guide.overview': 1,
|
||||
'.angular': 7,
|
||||
'.angular.Array': 7,
|
||||
'.angular.Object': 7,
|
||||
'.angular.directive': 7,
|
||||
'.angular.filter': 7,
|
||||
'.angular.formatter': 7,
|
||||
'.angular.scope': 7,
|
||||
'.angular.service': 7,
|
||||
'.angular.validator': 7,
|
||||
'.angular.widget': 7
|
||||
};
|
||||
function keywordSort(a, b){
|
||||
function mangleName(doc) {
|
||||
var path = doc.id.split(/\./);
|
||||
var mangled = [];
|
||||
var partialName = '';
|
||||
path.forEach(function(name){
|
||||
partialName += '.' + name;
|
||||
mangled.push(KEYWORD_PRIORITY[partialName] || 5);
|
||||
mangled.push(name);
|
||||
});
|
||||
return mangled.join('.');
|
||||
}
|
||||
|
||||
var namespacedA = namespacedName(a),
|
||||
namespacedB = namespacedName(b);
|
||||
|
||||
return namespacedA < namespacedB ? -1 : 1;
|
||||
var nameA = mangleName(a);
|
||||
var nameB = mangleName(b);
|
||||
return nameA < nameB ? -1 : (nameA > nameB ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
function trim(text) {
|
||||
function trim(text, prefix) {
|
||||
var MAX = 9999;
|
||||
var empty = RegExp.prototype.test.bind(/^\s*$/);
|
||||
var lines = text.split('\n');
|
||||
var minIndent = MAX;
|
||||
prefix = prefix || '';
|
||||
lines.forEach(function(line){
|
||||
minIndent = Math.min(minIndent, indent(line));
|
||||
});
|
||||
for ( var i = 0; i < lines.length; i++) {
|
||||
lines[i] = lines[i].substring(minIndent);
|
||||
lines[i] = prefix + lines[i].substring(minIndent);
|
||||
}
|
||||
// remove leading lines
|
||||
while (empty(lines[0])) {
|
||||
|
|
|
|||
|
|
@ -58,11 +58,22 @@
|
|||
function indent(text) {
|
||||
var lines = text.split(/\n/);
|
||||
var lineNo = [];
|
||||
// remove any leading blank lines
|
||||
while (lines[0].match(/^\s*$/)) lines.shift();
|
||||
// remove any trailing blank lines
|
||||
while (lines[lines.length - 1].match(/^\s*$/)) lines.pop();
|
||||
var minIndent = 999;
|
||||
for ( var i = 0; i < lines.length; i++) {
|
||||
lines[i] = ' ' + lines[i];
|
||||
lineNo.push(6 + i);
|
||||
var line = lines[0];
|
||||
var indent = line.match(/^\s*/)[0];
|
||||
if (indent !== line && indent.length < minIndent) {
|
||||
minIndent = indent.length;
|
||||
}
|
||||
}
|
||||
|
||||
for ( var i = 0; i < lines.length; i++) {
|
||||
lines[i] = ' ' + lines[i].substring(minIndent);
|
||||
lineNo.push(5 + i);
|
||||
}
|
||||
return {html: lines.join('\n'), hilite: lineNo.join(',') };
|
||||
};
|
||||
|
|
|
|||
|
|
@ -181,11 +181,16 @@ a {
|
|||
}
|
||||
|
||||
#sidebar ul li.level-0 {
|
||||
margin-top: 0.5em;
|
||||
margin-left: 0em;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#sidebar ul li.level-0:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#sidebar ul li.level-1.level-angular {
|
||||
font-family: monospace;
|
||||
font-weight: normal;
|
||||
|
|
@ -211,6 +216,11 @@ a {
|
|||
font-family: monospace;
|
||||
}
|
||||
|
||||
#sidebar ul li.level-4 {
|
||||
margin-left: 4em;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
|
||||
/* Warning and Info Banners */
|
||||
|
||||
|
|
@ -282,3 +292,11 @@ a {
|
|||
#main::-webkit-scrollbar {
|
||||
background-color:#fff;
|
||||
}
|
||||
|
||||
/* Content */
|
||||
img.right {
|
||||
float: right;
|
||||
}
|
||||
h1, h2, h3, h4, h5 {
|
||||
clear: both;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ function DocsController($location, $browser, $window) {
|
|||
window.$root = this.$root;
|
||||
|
||||
this.getUrl = function(page){
|
||||
return '#!' + page.name;
|
||||
return '#!' + page.id;
|
||||
};
|
||||
|
||||
this.getCurrentPartial = function(){
|
||||
|
|
@ -13,14 +13,14 @@ function DocsController($location, $browser, $window) {
|
|||
|
||||
this.getTitle = function(){
|
||||
var hashPath = $location.hashPath || '!angular';
|
||||
if (hashPath.match(/^!angular/)) {
|
||||
if (hashPath.match(/^!/)) {
|
||||
this.partialTitle = hashPath.substring(1);
|
||||
}
|
||||
return this.partialTitle;
|
||||
};
|
||||
|
||||
this.getClass = function(page) {
|
||||
var depth = page.name.split(/\./).length - 1,
|
||||
var depth = page.depth,
|
||||
cssClass = 'level-' + depth + (page.name == this.getTitle() ? ' selected' : '');
|
||||
|
||||
if (depth == 1 && page.type !== 'overview') cssClass += ' level-angular';
|
||||
|
|
@ -40,8 +40,4 @@ function DocsController($location, $browser, $window) {
|
|||
|
||||
}
|
||||
|
||||
angular.filter('short', function(name){
|
||||
return (name||'').split(/\./).pop();
|
||||
});
|
||||
|
||||
SyntaxHighlighter['defaults'].toolbar = false;
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@
|
|||
tabindex="1" accesskey="s"/>
|
||||
<ul id="api-list">
|
||||
<li ng:repeat="page in pages.$filter(search)" ng:class="getClass(page)">
|
||||
<a href="{{getUrl(page)}}" ng:click="" tabindex="2">{{page.name | short}}</a>
|
||||
<a href="{{getUrl(page)}}" ng:click="" tabindex="2">{{page.shortName}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -50,12 +50,27 @@ exports.makeDir = function (path, callback) {
|
|||
};
|
||||
|
||||
exports.copy = function(filename, callback){
|
||||
//console.log('writing', OUTPUT_DIR + filename, '...');
|
||||
fs.readFile('docs/src/templates/' + filename, function(err, content){
|
||||
if (err) return callback.error(err);
|
||||
fs.writeFile(
|
||||
OUTPUT_DIR + filename,
|
||||
content,
|
||||
callback);
|
||||
});
|
||||
copy('docs/src/templates/' + filename, OUTPUT_DIR + filename, callback);
|
||||
};
|
||||
|
||||
function copy(from, to, callback) {
|
||||
//console.log('writing', to, '...');
|
||||
fs.readFile(from, function(err, content){
|
||||
if (err) return callback.error(err);
|
||||
fs.writeFile(to, content, callback);
|
||||
});
|
||||
}
|
||||
|
||||
exports.copyImages = function(callback) {
|
||||
exports.makeDir(OUTPUT_DIR + '/img', callback.waitFor(function(){
|
||||
fs.readdir('docs/img', callback.waitFor(function(err, files){
|
||||
if (err) return this.error(err);
|
||||
files.forEach(function(file){
|
||||
if (file.match(/\.(png|gif|jpg|jpeg)$/)) {
|
||||
copy('docs/img/' + file, OUTPUT_DIR + '/img/' + file, callback.waitFor());
|
||||
}
|
||||
});
|
||||
callback();
|
||||
}));
|
||||
}));
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue