mirror of
https://github.com/Hopiu/angular.js.git
synced 2026-03-16 23:30:23 +00:00
added remaining directives and search box.
This commit is contained in:
parent
625cc7609c
commit
7e6f999221
15 changed files with 522 additions and 49 deletions
|
|
@ -7,8 +7,7 @@ var fs = require('fs'),
|
|||
Showdown = require('showdown').Showdown;
|
||||
|
||||
var documentation = {
|
||||
section:{},
|
||||
all:[]
|
||||
pages:[]
|
||||
};
|
||||
|
||||
var SRC_DIR = "docs/";
|
||||
|
|
@ -24,9 +23,7 @@ var work = callback.chain(function () {
|
|||
parseNgDoc(doc);
|
||||
if (doc.ngdoc) {
|
||||
delete doc.raw.text;
|
||||
var section = documentation.section;
|
||||
(section[doc.ngdoc] = section[doc.ngdoc] || []).push(doc);
|
||||
documentation.all.push(doc);
|
||||
documentation.pages.push(doc);
|
||||
console.log('Found:', doc.ngdoc + ':' + doc.shortName);
|
||||
mergeTemplate(
|
||||
doc.ngdoc + '.template',
|
||||
|
|
@ -38,6 +35,7 @@ var work = callback.chain(function () {
|
|||
}).onError(function(err){
|
||||
console.log('ERROR:', err.stack || err);
|
||||
}).onDone(function(){
|
||||
documentation.pages.sort(function(a,b){ return a.name == b.name ? 0:(a.name < b.name ? -1 : 1);});
|
||||
mergeTemplate('docs-data.js', 'docs-data.js', {JSON:JSON.stringify(documentation)}, callback.chain());
|
||||
mergeTemplate('docs-scenario.js', 'docs-scenario.js', documentation, callback.chain());
|
||||
copy('docs-scenario.html', callback.chain());
|
||||
|
|
@ -128,12 +126,16 @@ function escapedHtmlTag(doc, name, value) {
|
|||
|
||||
function markdownTag(doc, name, value) {
|
||||
doc[name] = markdown(value.replace(/^#/gm, '##')).
|
||||
replace(/\<pre\>/gmi, '<pre class="brush: xml; brush: js;" ng:non-bindable>');
|
||||
replace(/\<pre\>/gmi, '<div ng:non-bindable><pre class="brush: js; html-script: true; toolbar: false;">').
|
||||
replace(/\<\/pre\>/gmi, '</pre></div>');
|
||||
}
|
||||
|
||||
function markdown(text) {
|
||||
text = text.replace(/<angular\/>/gm, '<tt><angular/></tt>');
|
||||
return new Showdown.converter().makeHtml(text);
|
||||
text = text.replace(/(angular\.[\w\._\-:]+)/gm, '<a href="#$1">$1</a>');
|
||||
text = text.replace(/(`(ng:[\w\._\-]+)`)/gm, '<a href="#angular.directive.$2">$1</a>');
|
||||
text = new Showdown.converter().makeHtml(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
function markdownNoP(text) {
|
||||
|
|
@ -161,8 +163,8 @@ var TAG = {
|
|||
element: valueTag,
|
||||
name: function(doc, name, value) {
|
||||
doc.name = value;
|
||||
var match = value.match(/^angular[\.\#](([^\.]+)\.(.*)|(.*))/);
|
||||
doc.shortName = match[3] || match[4];
|
||||
doc.shortName = value.split(/\./).pop();
|
||||
doc.depth = value.split(/\./).length - 1;
|
||||
},
|
||||
param: function(doc, name, value){
|
||||
doc.param = doc.param || [];
|
||||
|
|
|
|||
|
|
@ -35,3 +35,5 @@
|
|||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
||||
</doc:example>
|
||||
{{/example}}
|
||||
|
||||
<script>SyntaxHighlighter.highlight();</script>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
{{#all}}
|
||||
{{#pages}}
|
||||
describe('{{name}}', function(){
|
||||
beforeEach(function(){
|
||||
browser().navigateTo('index.html#{{name}}');
|
||||
|
|
@ -6,4 +6,4 @@ describe('{{name}}', function(){
|
|||
// {{raw.file}}:{{raw.line}}
|
||||
{{{scenario}}}
|
||||
});
|
||||
{{/all}}
|
||||
{{/pages}}
|
||||
|
|
|
|||
|
|
@ -31,3 +31,5 @@ var modelValue = angular.formatter.{{shortName}}.parse(userInputString);
|
|||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
||||
</doc:example>
|
||||
{{/example}}
|
||||
|
||||
<script>SyntaxHighlighter.highlight();</script>
|
||||
|
|
|
|||
111
docs/index.html
111
docs/index.html
|
|
@ -26,18 +26,22 @@
|
|||
};
|
||||
|
||||
this.getCurrentPartial = function(){
|
||||
if ($location.hashPath.match(/^angular\./)) {
|
||||
this.partialUrl = './' + $location.hashPath + '.html';
|
||||
}
|
||||
return this.partialUrl;
|
||||
return './' + this.getTitle() + '.html';
|
||||
}
|
||||
|
||||
this.getTitle = function(){
|
||||
if ($location.hashPath.match(/^angular\./)) {
|
||||
this.partialTitle = $location.hashPath;
|
||||
var hashPath = $location.hashPath || 'angular';
|
||||
if (hashPath.match(/^angular/)) {
|
||||
this.partialTitle = hashPath;
|
||||
}
|
||||
return this.partialTitle;
|
||||
}
|
||||
|
||||
this.getClass = function(page) {
|
||||
return 'level-' + page.depth +
|
||||
(page.name == this.getTitle() ? ' selected' : '');
|
||||
};
|
||||
|
||||
}
|
||||
</script>
|
||||
<style type="text/css" media="screen">
|
||||
|
|
@ -47,12 +51,20 @@
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
#sidebar {
|
||||
width: 15em;
|
||||
float: left;
|
||||
|
||||
a {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
|
||||
.nav-section {
|
||||
margin-left: 1em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#header {
|
||||
background-color: #F2C200;
|
||||
margin-bottom: 1em;
|
||||
|
|
@ -95,11 +107,27 @@
|
|||
#section h1 {
|
||||
font-family: monospace;
|
||||
margin-top: 0;
|
||||
padding-bottom: 5px;
|
||||
border-bottom: 1px solid #CCC;
|
||||
}
|
||||
|
||||
#sidebar h2 {
|
||||
font-size: 1.2em;
|
||||
margin: 5px 5px 5px 0.8em;
|
||||
#sidebar {
|
||||
width: 180px;
|
||||
float: left;
|
||||
padding-left: 1em;
|
||||
}
|
||||
|
||||
#sidebar a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#sidebar a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#sidebar input {
|
||||
width: 175px;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
#sidebar ul {
|
||||
|
|
@ -110,18 +138,39 @@
|
|||
}
|
||||
|
||||
#sidebar ul li {
|
||||
margin: 0;
|
||||
padding: 1px 1px 1px 1.5em;
|
||||
}
|
||||
|
||||
.nav-section {
|
||||
margin-left: 1em;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
float: right;
|
||||
#sidebar ul li a {
|
||||
display: block;
|
||||
padding: 2px 2px 2px 4px;
|
||||
}
|
||||
|
||||
#sidebar ul li.selected a {
|
||||
background-color: #DDD;
|
||||
border-radius: 5px;
|
||||
-moz-border-radius: 5px;
|
||||
border: 1px solid #CCC;
|
||||
padding: 1px 1px 1px 3px;
|
||||
}
|
||||
|
||||
#sidebar ul li.level-0 {
|
||||
margin-left: 0em;
|
||||
font-weight: bold;
|
||||
font-size: 1.2em;
|
||||
}
|
||||
|
||||
#sidebar ul li.level-1 {
|
||||
margin-left: 1em;
|
||||
margin-top: 5px;
|
||||
font-size: 1.1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
#sidebar ul li.level-2 {
|
||||
margin-left: 2em;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
</style>
|
||||
<title><angular/>: {{getTitle()}}</title>
|
||||
</head>
|
||||
|
|
@ -133,14 +182,14 @@
|
|||
</h1>
|
||||
</div>
|
||||
<div id="sidebar" class="nav">
|
||||
<div ng:repeat="(name, type) in docs.section" class="nav-section">
|
||||
<h2>{{name}}</h2>
|
||||
<ul>
|
||||
<li ng:repeat="page in type.$orderBy('shortName')">
|
||||
<a href="{{getUrl(page)}}" ng:click="">{{page.shortName}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" name="filterText" placeholder="search documentaiton"/>
|
||||
<ul>
|
||||
<li ng:repeat="page in docs.pages.$filter(filterText)" ng:class="getClass(page)">
|
||||
<a href="{{getUrl(page)}}" ng:click="">{{page.shortName}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div id="section">
|
||||
<ng:include src="getCurrentPartial()"></ng:include>
|
||||
|
|
|
|||
|
|
@ -13,3 +13,5 @@
|
|||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
||||
</doc:example>
|
||||
{{/example}}
|
||||
|
||||
<script>SyntaxHighlighter.highlight();</script>
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ describe('collect', function(){
|
|||
|
||||
describe('@describe', function(){
|
||||
it('should support pre blocks', function(){
|
||||
TAG.description(doc, 'description', '<pre class="brush: xml;" ng:non-bindable>abc</pre>');
|
||||
expect(doc.description).toEqual('<pre class="brush: xml;" ng:non-bindable>abc</pre>');
|
||||
TAG.description(doc, 'description', '<pre>abc</pre>');
|
||||
expect(doc.description).toEqual('<div ng:non-bindable><pre class="brush: js; html-script: true; toolbar: false;">abc</pre></div>');
|
||||
});
|
||||
|
||||
describe('@example', function(){
|
||||
|
|
|
|||
|
|
@ -37,3 +37,5 @@ angular.validator.{{shortName}}({{paramFirst.name}}{{#paramRest}}{{^default}}, {
|
|||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
||||
</doc:example>
|
||||
{{/example}}
|
||||
|
||||
<script>SyntaxHighlighter.highlight();</script>
|
||||
|
|
|
|||
|
|
@ -37,3 +37,5 @@
|
|||
<doc:scenario>{{{scenario}}}</doc:scenario>
|
||||
</doc:example>
|
||||
{{/example}}
|
||||
|
||||
<script>SyntaxHighlighter.highlight();</script>
|
||||
|
|
|
|||
191
src/Angular.js
191
src/Angular.js
|
|
@ -1,3 +1,12 @@
|
|||
/**
|
||||
* @ngdoc overview
|
||||
* @name angular
|
||||
* @namespace Namespace for angular.
|
||||
* @description
|
||||
* Hello world!
|
||||
*
|
||||
* @example
|
||||
*/
|
||||
////////////////////////////////////
|
||||
|
||||
if (typeof document.getAttribute == $undefined)
|
||||
|
|
@ -91,6 +100,67 @@ var _undefined = undefined,
|
|||
angular = window[$angular] || (window[$angular] = {}),
|
||||
angularTextMarkup = extensionMap(angular, 'markup'),
|
||||
angularAttrMarkup = extensionMap(angular, 'attrMarkup'),
|
||||
/**
|
||||
* @ngdoc overview
|
||||
* @name angular.directive
|
||||
* @namespace Namespace for all directives.
|
||||
* @description
|
||||
* A directive is an XML attribute that you can use in an existing HTML
|
||||
* element type or in a DOM element type that you create using
|
||||
* `angular.widget`, to modify that element's properties. You can use
|
||||
* any number of directives per element.
|
||||
*
|
||||
* For example, you can add the ng:bind directive as an attribute of an
|
||||
* HTML span element, as in `<span ng:bind="1+2"></span>`.
|
||||
* How does this work? The compiler passes the attribute value `1+2`
|
||||
* to the ng:bind extension, which in turn tells the Scope to watch
|
||||
* that expression and report changes. On any change it sets the span
|
||||
* text to the expression value.
|
||||
*
|
||||
* Here's how to define ng:bind:
|
||||
* <pre>
|
||||
angular.directive('ng:bind', function(expression, compiledElement) {
|
||||
var compiler = this;
|
||||
return function(linkElement) {
|
||||
var currentScope = this;
|
||||
currentScope.$watch(expression, function(value) {
|
||||
linkElement.text(value);
|
||||
});
|
||||
};
|
||||
});
|
||||
* </pre>
|
||||
*
|
||||
* ## Directive vs. Attribute Widget
|
||||
* Both attribute widgets and directives can compile a DOM element
|
||||
* attribute. So why have two different ways to do the same thing?
|
||||
* The answer is that order matters, but you have no control over
|
||||
* the order in which attributes are read. To solve this we
|
||||
* apply attribute widget before the directive.
|
||||
*
|
||||
* For example, consider this piece of HTML, which uses the
|
||||
* directives `ng:repeat`, `ng:init`, and `ng:bind`:
|
||||
* <pre>
|
||||
<ul ng:init="people=['mike', 'mary']">
|
||||
<li ng:repeat="person in people" ng:init="a=a+1" ng:bind="person"></li>
|
||||
</ul>
|
||||
* </pre>
|
||||
*
|
||||
* Notice that the order of execution matters here. We need to
|
||||
* execute ng:repeat before we run the `ng:init` and `ng:bind`
|
||||
* on the `<li/>;`. This is because we want to run the
|
||||
* `ng:init="a=a+1` and `ng:bind="person"` once for each
|
||||
* person in people. We could not have used directive to
|
||||
* create this template because attributes are read in an
|
||||
* unspecified order and there is no way of guaranteeing
|
||||
* that the repeater attribute would execute first. Using
|
||||
* the `ng:repeat` attribute directive ensures that we can
|
||||
* transform the DOM element into a template.
|
||||
*
|
||||
* Widgets run before directives. Widgets are expected to
|
||||
* manipulate the DOM whereas directives are not expected
|
||||
* to manipulate the DOM, and they run last.
|
||||
*
|
||||
*/
|
||||
angularDirective = extensionMap(angular, 'directive'),
|
||||
|
||||
/**
|
||||
|
|
@ -332,7 +402,7 @@ var _undefined = undefined,
|
|||
* The formatters are responsible for translating user readable text in an input widget to a
|
||||
* data model stored in an application.
|
||||
*
|
||||
* # Writting your own Fromatter
|
||||
* # Writting your own Formatter
|
||||
* Writing your own formatter is easy. Just register a pair of JavaScript functions with
|
||||
* `angular.formatter`. One function for parsing user input text to the stored form,
|
||||
* and one for formatting the stored data to user-visible text.
|
||||
|
|
@ -391,7 +461,7 @@ var _undefined = undefined,
|
|||
*
|
||||
*
|
||||
* @scenario
|
||||
* it('should store reverse', function(){
|
||||
* iit('should store reverse', function(){
|
||||
* expect(element('.doc-example input:first').val()).toEqual('angular');
|
||||
* expect(element('.doc-example input:last').val()).toEqual('RALUGNA');
|
||||
*
|
||||
|
|
@ -399,7 +469,7 @@ var _undefined = undefined,
|
|||
* $document.elements('.doc-example input:last').val('XYZ').trigger('change');
|
||||
* done();
|
||||
* });
|
||||
* expect(element('input:first').val()).toEqual('zyx');
|
||||
* expect(element('.doc-example input:first').val()).toEqual('zyx');
|
||||
* });
|
||||
*/
|
||||
angularFormatter = extensionMap(angular, 'formatter'),
|
||||
|
|
@ -767,6 +837,121 @@ function toKeyValue(obj) {
|
|||
return parts.length ? parts.join('&') : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:autobind
|
||||
* @element script
|
||||
*
|
||||
* @description
|
||||
* This section explains how to bootstrap your application to
|
||||
* the <angular/> environment using either the
|
||||
* `angular-x.x.x.js` or `angular-x.x.x.min.js` script.
|
||||
*
|
||||
* ## The bootstrap code
|
||||
* Note that there are two versions of the bootstrap code that you can use:
|
||||
*
|
||||
* * `angular-x.x.x.js` - this file is unobfuscated, uncompressed, and thus
|
||||
* human-readable. Note that despite the name of the file, there is
|
||||
* no additional functionality built in to help you debug your
|
||||
* application; it has the prefix debug because you can read
|
||||
* the source code.
|
||||
* * `angular-x.x.x.min.js` - this is a compressed and obfuscated version
|
||||
* of `angular-x.x.x.js`. You might want to use this version if you
|
||||
* want to load a smaller but functionally equivalent version of the
|
||||
* code in your application. Note: this minified version was created
|
||||
* using the Closure Compiler.
|
||||
*
|
||||
*
|
||||
* ## Auto bind using: <tt>ng:autobind</tt>
|
||||
* The simplest way to get an <angular/> application up and running is by
|
||||
* inserting a script tag in your HTML file that bootstraps the
|
||||
* `http://code.angularjs.org/angular-x.x.x.min.js` code and uses the
|
||||
* special `ng:autobind` attribute, like in this snippet of HTML:
|
||||
*
|
||||
* <pre>
|
||||
<!doctype html>
|
||||
<html xmlns:ng="http://angularjs.org">
|
||||
<head>
|
||||
<script type="text/javascript" ng:autobind
|
||||
src="http://code.angularjs.org/angular-0.9.3.min.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
Hello {{'world'}}!
|
||||
</body>
|
||||
</html>
|
||||
* </pre>
|
||||
*
|
||||
* 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">
|
||||
<head>
|
||||
<script type="text/javascript" ng:autobind
|
||||
src="http://code.angularjs.org/angular-0.9.3.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>
|
||||
</head>
|
||||
<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 xmlsn 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:ng="http://angularjs.org" 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.
|
||||
*
|
||||
*/
|
||||
function angularInit(config){
|
||||
if (config.autobind) {
|
||||
// TODO default to the source of angular.js
|
||||
|
|
|
|||
|
|
@ -109,6 +109,57 @@ Compiler.prototype = {
|
|||
};
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:eval-order
|
||||
*
|
||||
* @description
|
||||
* Normally the view is updated from top to bottom. This usually is
|
||||
* not a problem, but under some circumstances the values for data
|
||||
* is not available until after the full view is computed. If such
|
||||
* values are needed before they are computed the order of
|
||||
* evaluation can be change using ng:eval-order
|
||||
*
|
||||
* @element ANY
|
||||
* @param {integer|string=} [priority=0] priority integer, or FIRST, LAST constant
|
||||
*
|
||||
* @exampleDescription
|
||||
* try changing the invoice and see that the Total will lag in evaluation
|
||||
* @example
|
||||
<div>TOTAL: without ng:eval-order {{ items.$sum('total') | currency }}</div>
|
||||
<div ng:eval-order='LAST'>TOTAL: with ng:eval-order {{ items.$sum('total') | currency }}</div>
|
||||
<table ng:init="items=[{qty:1, cost:9.99, desc:'gadget'}]">
|
||||
<tr>
|
||||
<td>QTY</td>
|
||||
<td>Description</td>
|
||||
<td>Cost</td>
|
||||
<td>Total</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr ng:repeat="item in items">
|
||||
<td><input name="item.qty"/></td>
|
||||
<td><input name="item.desc"/></td>
|
||||
<td><input name="item.cost"/></td>
|
||||
<td>{{item.total = item.qty * item.cost | currency}}</td>
|
||||
<td><a href="" ng:click="items.$remove(item)">X</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3"><a href="" ng:click="items.$add()">add</a></td>
|
||||
<td>{{ items.$sum('total') | currency }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
*
|
||||
* @scenario
|
||||
it('should check ng:format', function(){
|
||||
expect(using('.doc-example-live div:first').binding("items.$sum('total')")).toBe('$9.99');
|
||||
expect(using('.doc-example-live div:last').binding("items.$sum('total')")).toBe('$9.99');
|
||||
input('item.qty').enter('2');
|
||||
expect(using('.doc-example-live div:first').binding("items.$sum('total')")).toBe('$9.99');
|
||||
expect(using('.doc-example-live div:last').binding("items.$sum('total')")).toBe('$19.98');
|
||||
});
|
||||
*/
|
||||
|
||||
templatize: function(element, elementIndex, priority){
|
||||
var self = this,
|
||||
widget,
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ angularDirective("ng:eval", function(expression){
|
|||
* HTML element with the value of the given expression and kept it up to
|
||||
* date when the expression's value changes. Usually you just write
|
||||
* {{expression}} and let <angular/> compile it into
|
||||
* <span ng:bind="expression"></span> at bootstrap time.
|
||||
* `<span ng:bind="expression"></span>` at bootstrap time.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression to eval.
|
||||
|
|
@ -649,6 +649,7 @@ angularDirective("ng:submit", function(expression, element) {
|
|||
expect(using('.doc-example-live').binding('counter')).toBe('3');
|
||||
});
|
||||
*/
|
||||
//TODO: delete me, since having watch in UI is logic in UI. (leftover form getangular)
|
||||
angularDirective("ng:watch", function(expression, element){
|
||||
return function(element){
|
||||
var self = this;
|
||||
|
|
@ -862,15 +863,28 @@ angularDirective("ng:hide", function(expression, element){
|
|||
* @name angular.directive.ng:style
|
||||
*
|
||||
* @description
|
||||
* The ng:style allows you to set CSS style on an HTML element conditionally.
|
||||
*
|
||||
* @element ANY
|
||||
* @param {expression} expression to eval.
|
||||
* @param {expression} expression which evals to an object whes key's are
|
||||
* CSS style names and values are coresponding values for those
|
||||
* CSS keys.
|
||||
*
|
||||
* @exampleDescription
|
||||
* @example
|
||||
<input type="button" value="set" ng:click="myStyle={color:'red'}">
|
||||
<input type="button" value="clear" ng:click="myStyle={}">
|
||||
<br/>
|
||||
<span ng:style="myStyle">Sample Text</span>
|
||||
<pre>myStyle={{myStyle}}</pre>
|
||||
*
|
||||
* @scenario
|
||||
it('should check ng:style', function(){
|
||||
expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
|
||||
element('.doc-example-live :button[value=set]').click();
|
||||
expect(element('.doc-example-live span').css('color')).toBe('red');
|
||||
element('.doc-example-live :button[value=clear]').click();
|
||||
expect(element('.doc-example-live span').css('color')).toBe('rgb(0, 0, 0)');
|
||||
});
|
||||
*/
|
||||
angularDirective("ng:style", function(expression, element){
|
||||
|
|
|
|||
|
|
@ -68,6 +68,57 @@ angularTextMarkup('OPTION', function(text, textNode, parentElement){
|
|||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:href
|
||||
*
|
||||
* @description
|
||||
* Using <angular/> markup like {{hash}} in an href attribute makes
|
||||
* the page open to a wrong URL, ff the user clicks that link before
|
||||
* angular has a chance to replace the {{hash}} with actual URL, the
|
||||
* link will be broken and will most likely return a 404 error.
|
||||
* The `ng:href` solves this problem by placing the `href` in the
|
||||
* `ng:` namespace.
|
||||
*
|
||||
* The buggy way to write it:
|
||||
* <pre>
|
||||
* <a href="http://www.gravatar.com/avatar/{{hash}}"/>
|
||||
* </pre>
|
||||
*
|
||||
* The correct way to write it:
|
||||
* <pre>
|
||||
* <a ng:href="http://www.gravatar.com/avatar/{{hash}}"/>
|
||||
* </pre>
|
||||
*
|
||||
* @element ANY
|
||||
* @param {template} template any string which can contain `{{}}` markup.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:src
|
||||
*
|
||||
* @description
|
||||
* Using <angular/> markup like `{{hash}}` in a `src` attribute doesn't
|
||||
* work right: The browser will fetch from the URL with the literal
|
||||
* text `{{hash}}` until <angular/> replaces the expression inside
|
||||
* `{{hash}}`. The `ng:src` attribute solves this problem by placing
|
||||
* the `src` attribute in the `ng:` namespace.
|
||||
*
|
||||
* The buggy way to write it:
|
||||
* <pre>
|
||||
* <img src="http://www.gravatar.com/avatar/{{hash}}"/>
|
||||
* </pre>
|
||||
*
|
||||
* The correct way to write it:
|
||||
* <pre>
|
||||
* <img ng:src="http://www.gravatar.com/avatar/{{hash}}"/>
|
||||
* </pre>
|
||||
*
|
||||
* @element ANY
|
||||
* @param {template} template any string which can contain `{{}}` markup.
|
||||
*/
|
||||
|
||||
var NG_BIND_ATTR = 'ng:bind-attr';
|
||||
var SPECIAL_ATTRS = {'ng:src': 'src', 'ng:href': 'href'};
|
||||
angularAttrMarkup('{{}}', function(value, name, element){
|
||||
|
|
|
|||
|
|
@ -244,6 +244,7 @@ function parser(text, json){
|
|||
statements: statements,
|
||||
validator: validator,
|
||||
filter: filter,
|
||||
//TODO: delete me, since having watch in UI is logic in UI. (leftover form getangular)
|
||||
watch: watch
|
||||
};
|
||||
|
||||
|
|
@ -624,6 +625,7 @@ function parser(text, json){
|
|||
};
|
||||
}
|
||||
|
||||
//TODO: delete me, since having watch in UI is logic in UI. (leftover form getangular)
|
||||
function watch () {
|
||||
var decl = [];
|
||||
while(hasTokens()) {
|
||||
|
|
|
|||
109
src/widgets.js
109
src/widgets.js
|
|
@ -165,6 +165,82 @@ function compileValidator(expr) {
|
|||
return parser(expr).validator()();
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:validate
|
||||
*
|
||||
* @description
|
||||
* This directive validates the user input. If the input does not
|
||||
* pass validation, this sets an `ng-validation-error` CSS class and
|
||||
* an `ng:error` attribute on the input element. Visit validators to
|
||||
* find out more.
|
||||
*
|
||||
* @element INPUT
|
||||
* @css ng-validation-error
|
||||
* @param {function} validation call this function to validate input
|
||||
* falsy return means validation passed, To return error, simply
|
||||
* return the error string.
|
||||
*
|
||||
* @exampleDescription
|
||||
* @example
|
||||
I don't validate: <input type="text" name="value"><br/>
|
||||
I cannot be blank: <input type="text" name="value" ng:required><br/>
|
||||
I need an integer or nothing: <input type="text" name="value" ng:validate="integer"><br/>
|
||||
I must have an integer: <input type="text" name="value" ng:required ng:validate="integer"><br/>
|
||||
*
|
||||
* @scenario
|
||||
it('should check ng:validate', function(){
|
||||
expect(element('.doc-example-live :input:last').attr('className')).toMatch(/ng-validation-error/);
|
||||
input('value').enter('123');
|
||||
expect(element('.doc-example-live :input:last').attr('className')).not().toMatch(/ng-validation-error/);
|
||||
});
|
||||
*/
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:required
|
||||
*
|
||||
* @description
|
||||
* This directive requires the user input to be present.
|
||||
*
|
||||
* @element INPUT
|
||||
* @css ng-validation-error
|
||||
*
|
||||
* @exampleDescription
|
||||
* @example
|
||||
I cannot be blank: <input type="text" name="value" ng:required><br/>
|
||||
*
|
||||
* @scenario
|
||||
it('should check ng:required', function(){
|
||||
expect(element('.doc-example-live :input').attr('className')).toMatch(/ng-validation-error/);
|
||||
input('value').enter('123');
|
||||
expect(element('.doc-example-live :input').attr('className')).not().toMatch(/ng-validation-error/);
|
||||
});
|
||||
*/
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:format
|
||||
*
|
||||
* @description
|
||||
* The `ng:format` directive formats stored data to user-readable
|
||||
* text and parses the text back to the stored form. You might
|
||||
* find this useful for example if you collect user input in a
|
||||
* text field but need to store the data in the model as a list.
|
||||
*
|
||||
* @element INPUT
|
||||
*
|
||||
* @exampleDescription
|
||||
* @example
|
||||
Enter a comma separated list of items:
|
||||
<input type="text" name="list" ng:format="list" value="table, chairs, plate">
|
||||
<pre>list={{list}}</pre>
|
||||
*
|
||||
* @scenario
|
||||
it('should check ng:format', function(){
|
||||
expect(binding('list')).toBe('list=["table","chairs","plate"]');
|
||||
input('list').enter(',,, a ,,,');
|
||||
expect(binding('list')).toBe('list=["a"]');
|
||||
});
|
||||
*/
|
||||
function valueAccessor(scope, element) {
|
||||
var validatorName = element.attr('ng:validate') || NOOP,
|
||||
validator = compileValidator(validatorName),
|
||||
|
|
@ -320,6 +396,39 @@ function radioInit(model, view, element) {
|
|||
view.set(modelValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name angular.directive.ng:change
|
||||
*
|
||||
* @description
|
||||
* The directive executes an expression whenever the input widget changes.
|
||||
*
|
||||
* @element INPUT
|
||||
* @param {expression} expression to execute.
|
||||
*
|
||||
* @exampleDescription
|
||||
* @example
|
||||
<div ng:init="checkboxCount=0; textCount=0"></div>
|
||||
<input type="text" name="text" ng:change="textCount = 1 + textCount">
|
||||
changeCount {{textCount}}<br/>
|
||||
<input type="checkbox" name="checkbox" ng:change="checkboxCount = 1 + checkboxCount">
|
||||
changeCount {{checkboxCount}}<br/>
|
||||
*
|
||||
* @scenario
|
||||
it('should check ng:change', function(){
|
||||
expect(binding('textCount')).toBe('0');
|
||||
expect(binding('checkboxCount')).toBe('0');
|
||||
|
||||
using('.doc-example-live').input('text').enter('abc');
|
||||
expect(binding('textCount')).toBe('1');
|
||||
expect(binding('checkboxCount')).toBe('0');
|
||||
|
||||
|
||||
using('.doc-example-live').input('checkbox').check();
|
||||
expect(binding('textCount')).toBe('1');
|
||||
expect(binding('checkboxCount')).toBe('1');
|
||||
});
|
||||
*/
|
||||
function inputWidget(events, modelAccessor, viewAccessor, initFn) {
|
||||
return function(element) {
|
||||
var scope = this,
|
||||
|
|
|
|||
Loading…
Reference in a new issue