From bd33f60276a0fa37acffbad7a0cdcff92db594c8 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Tue, 25 Jan 2011 21:55:11 -0800 Subject: [PATCH] Added part of guide documentation and supporting changes to doc generator --- docs/guide.bootstrap.ngdoc | 97 ++++++++++++++ docs/guide.compiler.ngdoc | 163 +++++++++++++++++++++++ docs/guide.data-binding.ngdoc | 41 ++++++ docs/guide.ngdoc | 36 +++++ docs/guide.overview.ngdoc | 166 +++++++++++++++++++++++ docs/guide.template.ngdoc | 22 ++++ docs/img/One_Way_Data_Binding.png | Bin 0 -> 32339 bytes docs/img/Two_Way_Data_Binding.png | Bin 0 -> 50276 bytes docs/spec/domSpec.js | 32 ++++- docs/spec/ngdocSpec.js | 119 ++++++++++++++--- docs/src/dom.js | 25 +++- docs/src/gen-docs.js | 5 +- docs/src/ngdoc.js | 210 ++++++++++++++++++------------ docs/src/templates/doc_widgets.js | 15 ++- docs/src/templates/docs.css | 18 +++ docs/src/templates/docs.js | 10 +- docs/src/templates/index.html | 2 +- docs/src/writer.js | 31 +++-- 18 files changed, 863 insertions(+), 129 deletions(-) create mode 100644 docs/guide.bootstrap.ngdoc create mode 100644 docs/guide.compiler.ngdoc create mode 100644 docs/guide.data-binding.ngdoc create mode 100644 docs/guide.ngdoc create mode 100644 docs/guide.overview.ngdoc create mode 100644 docs/guide.template.ngdoc create mode 100644 docs/img/One_Way_Data_Binding.png create mode 100644 docs/img/Two_Way_Data_Binding.png diff --git a/docs/guide.bootstrap.ngdoc b/docs/guide.bootstrap.ngdoc new file mode 100644 index 00000000..835fe494 --- /dev/null +++ b/docs/guide.bootstrap.ngdoc @@ -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: + + + + Hello {{'World'}}! + + + +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. + +
+
+
+ 
+ 
+ 
+  Hello {{'World'}}!
+ 
+
+
+ +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. + +
+
+
+ + +# 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: + +
+
+
+ + +# 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. + diff --git a/docs/guide.compiler.ngdoc b/docs/guide.compiler.ngdoc new file mode 100644 index 00000000..8896db43 --- /dev/null +++ b/docs/guide.compiler.ngdoc @@ -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 , which should display a greeting. + +If we want this HTML source: + +
+
+ +
+
+ +To produce this DOM: + +
+
+ + Hello + World! + +
+
+ +Write this widget definition (assuming you've already declared the my namespace in the page): + + +
+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('');
+    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);
+    });
+  };
+});
+
+ +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 element set to the salutation class + * Create a 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. + diff --git a/docs/guide.data-binding.ngdoc b/docs/guide.data-binding.ngdoc new file mode 100644 index 00000000..12a926bd --- /dev/null +++ b/docs/guide.data-binding.ngdoc @@ -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 + + +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 + +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}. diff --git a/docs/guide.ngdoc b/docs/guide.ngdoc new file mode 100644 index 00000000..b1ac143e --- /dev/null +++ b/docs/guide.ngdoc @@ -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. diff --git a/docs/guide.overview.ngdoc b/docs/guide.overview.ngdoc new file mode 100644 index 00000000..d4615f88 --- /dev/null +++ b/docs/guide.overview.ngdoc @@ -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. + + + + QTY: + * + Cost: + = + {{qty * cost | currency}} + + + 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'); + }); + + + +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: + +
+Hello
+
+ +In programmatic systems you would have to write and run code like this: + +
+var label = new Label();
+label.setText('Hello');
+label.setClass('label');
+parent.addChild(label);
+
+ +## 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 + + + + + + + + +{@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} diff --git a/docs/guide.template.ngdoc b/docs/guide.template.ngdoc new file mode 100644 index 00000000..ae9bba92 --- /dev/null +++ b/docs/guide.template.ngdoc @@ -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. diff --git a/docs/img/One_Way_Data_Binding.png b/docs/img/One_Way_Data_Binding.png new file mode 100644 index 0000000000000000000000000000000000000000..60e7e3bf325552d6bae24f19b59f757dc2dfae1e GIT binary patch literal 32339 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 literal 0 HcmV?d00001 diff --git a/docs/img/Two_Way_Data_Binding.png b/docs/img/Two_Way_Data_Binding.png new file mode 100644 index 0000000000000000000000000000000000000000..3a9c6d1ecc2514d855b2384ffb279c1083359928 GIT binary patch literal 50276 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
*6oT0`S-j1^e^Dm?<{Wxng~O)hYmV$y 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\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('

Example

\n' + '
' + @@ -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('
src
'); }); + }); + + 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('

sub-heading

'); + }); + expect(dom.toString()).toContain('

heading

'); + expect(dom.toString()).toContain('

sub-heading

'); + }); }); + }); diff --git a/docs/spec/ngdocSpec.js b/docs/spec/ngdocSpec.js index 8f57e329..9d84ee7e 100644 --- a/docs/spec/ngdocSpec.js +++ b/docs/spec/ngdocSpec.js @@ -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 element', function(){ + var doc = new Doc('@description before ' + + '\n<>\n after'); + doc.parse(); + expect(doc.description).toContain('

before

' + + '\n<>\n

after

'); + }); + + it('should escape element', function(){ + var doc = new Doc('@description before ' + + '\n<>\n after'); + doc.parse(); + expect(doc.description).toContain('

before

' + + '\n<>\n

after

'); + }); + + 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 ', function(){ + var doc = new Doc( + '@id id\n' + + '@description scenario0' + + '@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
 tags', function() {
       expect(markdown('
x
# One
b
')). - toMatch('

One

One

foo

' + '
abc
' + - '

bah

\n\n' + + '

bah

\n\n' + '

foo

' + '
cba
'); @@ -243,18 +322,15 @@ describe('ngdoc', function(){ '{@link angular.directive.ng:foo ng:foo}'); doc.parse(); expect(doc.description). - toBe('

foo angular.foo

\n\n' + - '

da bar foo bar

\n\n' + - '

dadangular.foo

\n\n' + - '

ng:foo

'); + toContain('foo angular.foo'); + expect(doc.description). + toContain('da bar foo bar'); + expect(doc.description). + toContain('dadangular.foo'); + expect(doc.description). + toContain('ng:foo'); }); - 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('

foo

\n\n

abc

\n\n

bar

\n\n

xyz

'); - }); }); 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('

heading

'); + expect(doc.html()).not.toContain('Description'); + }); + }); + + describe('filter', function(){ it('should format', function(){ var doc = new Doc({ diff --git a/docs/src/dom.js b/docs/src/dom.js index fedd4e19..7708cbc9 100644 --- a/docs/src/dom.js +++ b/docs/src/dom.js @@ -3,12 +3,18 @@ */ exports.DOM = DOM; +exports.htmlEscape = htmlEscape; ////////////////////////////////////////////////////////// +function htmlEscape(text){ + return text.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, '>')); + 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); } diff --git a/docs/src/gen-docs.js b/docs/src/gen-docs.js index a287a2be..7e17ea8f 100644 --- a/docs/src/gen-docs.js +++ b/docs/src/gen-docs.js @@ -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()); diff --git a/docs/src/ngdoc.js b/docs/src/ngdoc.js index 7fb9af73..e01d9ccf 100644 --- a/docs/src/ngdoc.js +++ b/docs/src/ngdoc.js @@ -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(/([\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(/(
[\s\S]*?<\/pre>)/),
+  var parts = text.split(/(
[\s\S]*?<\/pre>|[\s\S]*?<\/doc:example>)/),
       match;
 
   parts.forEach(function(text, i){
@@ -443,39 +449,51 @@ function markdown (text) {
                 content.replace(//g, '>') +
                '
'; }); + } else if (text.match(/^/)) { + text = text.replace(/()([\s\S]*)(<\/doc:source>)/mi, + function(_, before, content, after){ + return before + htmlEscape(content) + after; + }); + text = text.replace(/()([\s\S]*)(<\/doc:scenario>)/mi, + function(_, before, content, after){ + return before + htmlEscape(content) + after; + }); } else { text = text.replace(//gm, '<angular/>'); - text = new Showdown.converter().makeHtml(text.replace(/^#/gm, '###')); - - while (match = text.match(R_LINK)) { - text = text.replace(match[0], '' + - (match[4] || match[1]) + - ''); - } + text = text.replace(/{@link ([^\s}]+)((\s|\n)+(.+?))?\s*}/gm, + function(_all, url, _2, _3, title){ + return '' + + (url.match(/^angular\./) ? '' : '') + + (title || url) + + (url.match(/^angular\./) ? '' : '') + + ''; + }); + 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])) { diff --git a/docs/src/templates/doc_widgets.js b/docs/src/templates/doc_widgets.js index 2d1ab8c6..39b9ff48 100644 --- a/docs/src/templates/doc_widgets.js +++ b/docs/src/templates/doc_widgets.js @@ -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(',') }; }; diff --git a/docs/src/templates/docs.css b/docs/src/templates/docs.css index a687ce87..a7566e79 100644 --- a/docs/src/templates/docs.css +++ b/docs/src/templates/docs.css @@ -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; +} diff --git a/docs/src/templates/docs.js b/docs/src/templates/docs.js index f1cfc3e7..aaea8c9d 100644 --- a/docs/src/templates/docs.js +++ b/docs/src/templates/docs.js @@ -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; diff --git a/docs/src/templates/index.html b/docs/src/templates/index.html index bb80a4ba..538be297 100644 --- a/docs/src/templates/index.html +++ b/docs/src/templates/index.html @@ -34,7 +34,7 @@ tabindex="1" accesskey="s"/> diff --git a/docs/src/writer.js b/docs/src/writer.js index c72a54a4..953302d4 100644 --- a/docs/src/writer.js +++ b/docs/src/writer.js @@ -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(); + })); + })); };