fixed example rendering, add tests for it.

This commit is contained in:
Misko Hevery 2011-01-19 15:42:11 -08:00
parent 5d0d34ae72
commit c2f2587a79
46 changed files with 512 additions and 477 deletions

View file

@ -8,13 +8,13 @@ The formatters are responsible for translating user readable text in an input wi
data model stored in an application.
# 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,
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.
Here is an example of a "reverse" formatter: The data is stored in uppercase and in
reverse, while it is displayed in lower case and non-reversed. User edits are
automatically parsed into the internal form and data changes are automatically
Here is an example of a "reverse" formatter: The data is stored in uppercase and in
reverse, while it is displayed in lower case and non-reversed. User edits are
automatically parsed into the internal form and data changes are automatically
formatted to the viewed form.
<pre>
@ -56,11 +56,11 @@ angular.formatter('reverse', {
});
</script>
Formatted:
Formatted:
<input type="text" name="data" value="angular" ng:format="reverse"/>
<br/>
Stored:
Stored:
<input type="text" name="data"/><br/>
<pre>{{data}}</pre>
@ -69,7 +69,7 @@ Stored:
it('should store reverse', function(){
expect(element('.doc-example input:first').val()).toEqual('angular');
expect(element('.doc-example input:last').val()).toEqual('RALUGNA');
this.addFutureAction('change to XYZ', function($window, $document, done){
$document.elements('.doc-example input:last').val('XYZ').trigger('change');
done();

View file

@ -76,7 +76,7 @@ window alert.
};
}, {$inject: ['$window']});
</pre>
And here is a unit test for this service. We use Jasmine spy (mock) instead of real browser's alert.
<pre>
var mock, notify;
@ -85,7 +85,7 @@ beforeEach(function() {
mock = {alert: jasmine.createSpy()};
notify = angular.service('notify')(mock);
});
it('should not alert first two notifications', function() {
notify('one');
notify('two');
@ -134,7 +134,7 @@ function myController($loc, $log) {
};
}
// which services to inject ?
myController.$inject = ['$location', '$log'];
myController.$inject = ['$location', '$log'];
</pre>
@example
@ -149,13 +149,13 @@ myController.$inject = ['$location', '$log'];
}
};
}, {$inject: ['$window']});
function myController(notifyService) {
this.callNotify = function(msg) {
notifyService(msg);
};
}
myController.$inject = ['notify'];
</script>

View file

@ -4,7 +4,7 @@
@namespace Namespace for all filters.
@description
# Overview
Validators are a standard way to check the user input against a specific criteria. For
Validators are a standard way to check the user input against a specific criteria. For
example, you might need to check that an input field contains a well-formed phone number.
# Syntax
@ -29,10 +29,10 @@ Attach a validator on user input widgets using the `ng:validate` attribute.
# Writing your own Validators
Writing your own validator is easy. To make a function available as a
validator, just define the JavaScript function on the `angular.validator`
object. <angular/> passes in the input to validate as the first argument
to your function. Any additional validator arguments are passed in as
Writing your own validator is easy. To make a function available as a
validator, just define the JavaScript function on the `angular.validator`
object. <angular/> passes in the input to validate as the first argument
to your function. Any additional validator arguments are passed in as
additional arguments to your function.
You can use these variables in the function:
@ -40,9 +40,9 @@ You can use these variables in the function:
* `this` — The current scope.
* `this.$element` — The DOM element containing the binding. This allows the filter to manipulate
the DOM in addition to transforming the input.
In this example we have written a upsTrackingNo validator.
It marks the input text "valid" only when the user enters a well-formed
In this example we have written a upsTrackingNo validator.
It marks the input text "valid" only when the user enters a well-formed
UPS tracking number.
@css ng-validation-error
@ -57,7 +57,7 @@ UPS tracking number.
});
</script>
<input type="text" name="trackNo" size="40"
ng:validate="upsTrackingNo:'1Z 999 999 99 9999 999 9'"
ng:validate="upsTrackingNo:'1Z 999 999 99 9999 999 9'"
value="1Z 123 456 78 9012 345 6"/>
@scenario

View file

@ -4,19 +4,19 @@
@namespace Namespace for all widgets.
@description
# Overview
Widgets allow you to create DOM elements that the browser doesn't
already understand. You create the widget in your namespace and
assign it behavior. You can only bind one widget per DOM element
(unlike directives, in which you can use any number per DOM
element). Widgets are expected to manipulate the DOM tree by
Widgets allow you to create DOM elements that the browser doesn't
already understand. You create the widget in your namespace and
assign it behavior. You can only bind one widget per DOM element
(unlike directives, in which you can use any number per DOM
element). Widgets are expected to manipulate the DOM tree by
adding new elements whereas directives are expected to only modify
element properties.
Widgets come in two flavors: element and attribute.
# Element Widget
Let's say we would like to create a new element type in the
namespace `my` that can watch an expression and alert() the user
Let's say we would like to create a new element type in the
namespace `my` that can watch an expression and alert() the user
with each new value.
<pre>
@ -38,7 +38,7 @@ angular.widget('my:watch', function(compileElement) {
</pre>
# Attribute Widget
Let's implement the same widget, but this time as an attribute
Let's implement the same widget, but this time as an attribute
that can be added to any existing DOM element.
<pre>
&lt;div my-watch="name"&gt;text&lt;/div&gt;
@ -70,4 +70,4 @@ angular.widget('@my:watch', function(expression, compileElement) {
});
</script>
<my:time></my:time>

View file

@ -54,4 +54,4 @@
</doc:source>
{{#scenario}}<doc:scenario>{{{scenario}}}</doc:scenario>{{/scenario}}
</doc:example>
{{/example}}
{{/example}}

24
docs/spec/domSpec.js Normal file
View file

@ -0,0 +1,24 @@
var DOM = require('dom.js').DOM;
describe('dom', function(){
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>\ndesc<doc:example><doc:source>src</doc:source>\n<doc:scenario>scenario</doc:scenario>\n</doc:example>\n');
});
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>\ndesc<div ng:non-bindable=""><pre class="brush: js; html-script: true;">src</pre>\n</div>\n');
});
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>');
});
});
});

View file

@ -279,6 +279,16 @@ describe('ngdoc', function(){
doc.parse();
expect(doc.html()).toContain('<p>some\n text');
});
it('should render description in related method', function(){
var doc = new Doc();
doc.ngdoc = 'service';
doc.methods = [new Doc('@ngdoc method\n@exampleDescription MDesc\n@example MExmp').parse()];
doc.properties = [new Doc('@ngdoc property\n@exampleDescription PDesc\n@example PExmp').parse()];
expect(doc.html()).toContain('<p>MDesc</p><div ng:non-bindable=""><pre class="brush: js; html-script: true;">MExmp</pre>');
expect(doc.html()).toContain('<p>PDesc</p><div ng:non-bindable=""><pre class="brush: js; html-script: true;">PExmp</pre>');
});
});
describe('@deprecated', function() {

View file

@ -2,17 +2,17 @@ var writer = require('writer.js');
describe('writer', function(){
describe('toString', function(){
var toString = writer.toString;
it('should merge string', function(){
expect(toString('abc')).toEqual('abc');
});
it('should merge obj', function(){
expect(toString({a:1})).toEqual('{"a":1}');
});
it('should merge array', function(){
expect(toString(['abc',{}])).toEqual('abc{}');
});
});
});
});

View file

@ -38,7 +38,7 @@ var writes = callback.chain(function(){
writer.copy('jquery.min.js', writes.waitFor());
});
writes.onDone(function(){
console.log('DONE. Generated ' + docs.length + ' pages in ' +
console.log('DONE. Generated ' + docs.length + ' pages in ' +
(now()-start) + 'ms.' );
});
work.onDone(writes);

View file

@ -76,6 +76,7 @@ Doc.prototype = {
this.description = markdown(this.description);
this['this'] = markdown(this['this']);
this.exampleDescription = markdown(this.exampleDescription || this.exampleDesc);
return this;
function flush(){
if (atName) {
@ -144,13 +145,13 @@ Doc.prototype = {
dom.h(method.shortName + '(' + signature.join(', ') + ')', method, function(){
dom.html(method.description);
method.html_usage_parameters(dom);
dom.example(method.example, false);
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.example, false);
dom.example(property.exampleDescription, property.example, false);
});
});

View file

@ -88,4 +88,4 @@ function findNgDocInJsFile(file, callback) {
exports.collect = collect;
exports.collect = collect;

View file

@ -32,4 +32,4 @@ li.doc-example-live {
div.syntaxhighlighter {
padding-bottom: 1px !important; /* fix to remove unnecessary scrollbars http://is.gd/gSMgC */
}
}

View file

@ -1,5 +1,5 @@
(function(){
var angularJsUrl;
var scripts = document.getElementsByTagName("script");
var filename = /(.*\/)angular([^\/]*)/;
@ -10,7 +10,7 @@
}
}
var HTML_TEMPLATE =
'<!doctype html>\n' +
'<html xmlns:ng="http://angularjs.org">\n' +
@ -32,15 +32,15 @@
var tabs = angular.element(
'<ul class="doc-example">' +
'<li class="doc-example-heading"><h3>Source</h3></li>' +
'<li class="doc-example-source" ng:non-bindable>' +
'<pre class="brush: js; html-script: true; highlight: [' +
'<li class="doc-example-source" ng:non-bindable>' +
'<pre class="brush: js; html-script: true; highlight: [' +
code.hilite + ']; toolbar: false;"></pre></li>' +
'<li class="doc-example-heading"><h3>Live Preview</h3></li>' +
'<li class="doc-example-live">' + exampleSrc +'</li>' +
'<li class="doc-example-heading"><h3>Scenario Test</h3></li>' +
'<li class="doc-example-scenario"><pre class="brush: js">' + scenario.text() + '</pre></li>' +
'</ul>');
tabs.find('li.doc-example-source > pre').text(HTML_TEMPLATE.replace('_HTML_SOURCE_', code.html));
element.html('');
@ -54,7 +54,7 @@
alert(e);
}
});
function indent(text) {
var lines = text.split(/\n/);
var lineNo = [];
@ -66,5 +66,5 @@
}
return {html: lines.join('\n'), hilite: lineNo.join(',') };
};
})();
})();

View file

@ -7,4 +7,4 @@
</head>
<body>
</body>
</html>
</html>

View file

@ -2,7 +2,7 @@ DocsController.$inject = ['$location', '$browser', '$window'];
function DocsController($location, $browser, $window) {
this.pages = NG_PAGES;
window.$root = this.$root;
this.getUrl = function(page){
return '#!' + page.name;
};
@ -10,7 +10,7 @@ function DocsController($location, $browser, $window) {
this.getCurrentPartial = function(){
return './' + this.getTitle() + '.html';
};
this.getTitle = function(){
var hashPath = $location.hashPath || '!angular';
if (hashPath.match(/^!angular/)) {
@ -18,7 +18,7 @@ function DocsController($location, $browser, $window) {
}
return this.partialTitle;
};
this.getClass = function(page) {
var depth = page.name.split(/\./).length - 1,
cssClass = 'level-' + depth + (page.name == this.getTitle() ? ' selected' : '');
@ -37,7 +37,7 @@ function DocsController($location, $browser, $window) {
"subject=" + escape("Feedback on " + $location.href) + "&" +
"body=" + escape("Hi there,\n\nI read " + $location.href + " and wanted to ask ....");
};
}
angular.filter('short', function(name){

View file

@ -7,7 +7,7 @@
*
* @version
* 3.0.83 (July 02 2010)
*
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
@ -29,7 +29,7 @@
;
var r = SyntaxHighlighter.regexLib;
this.regexList = [
{ regex: r.multiLineDoubleQuotedString, css: 'string' }, // double quoted strings
{ regex: r.multiLineSingleQuotedString, css: 'string' }, // single quoted strings
@ -38,7 +38,7 @@
{ regex: /\s*#.*/gm, css: 'preprocessor' }, // preprocessor tags like #region and #endregion
{ regex: new RegExp(this.getKeywords(keywords), 'gm'), css: 'keyword' } // keywords
];
this.forHtmlScript(r.scriptScriptTags);
};

View file

@ -7,7 +7,7 @@
*
* @version
* 3.0.83 (July 02 2010)
*
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*
@ -28,8 +28,8 @@
tag = new XRegExp('(&lt;|<)[\\s\\/\\?]*(?<name>[:\\w-\\.]+)', 'xg').exec(code),
result = []
;
if (match.attributes != null)
if (match.attributes != null)
{
var attributes,
regex = new XRegExp('(?<name> [\\w:\\-\\.]+)' +
@ -37,7 +37,7 @@
'(?<value> ".*?"|\'.*?\'|\\w+)',
'xg');
while ((attributes = regex.exec(code)) != null)
while ((attributes = regex.exec(code)) != null)
{
result.push(new constructor(attributes.name, match.index + attributes.index, 'color1'));
result.push(new constructor(attributes.value, match.index + attributes.index + attributes[0].indexOf(attributes.value), 'string'));
@ -51,7 +51,7 @@
return result;
}
this.regexList = [
{ regex: new XRegExp('(\\&lt;|<)\\!\\[[\\w\\s]*?\\[(.|\\s)*?\\]\\](\\&gt;|>)', 'gm'), css: 'color2' }, // <![ ... [ ... ]]>
{ regex: SyntaxHighlighter.regexLib.xmlComments, css: 'comments' }, // <!-- ... -->

View file

@ -7,7 +7,7 @@
*
* @version
* 3.0.83 (July 02 2010)
*
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*

View file

@ -7,7 +7,7 @@
*
* @version
* 3.0.83 (July 02 2010)
*
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*

View file

@ -7,7 +7,7 @@
*
* @version
* 3.0.83 (July 02 2010)
*
*
* @copyright
* Copyright (C) 2004-2010 Alex Gorbatchev.
*

View file

@ -13,17 +13,17 @@ function output(docs, content, callback){
exports.output = function(file, content, callback){
//console.log('writing', OUTPUT_DIR + file, '...');
fs.writeFile(
OUTPUT_DIR + file,
exports.toString(content),
OUTPUT_DIR + file,
exports.toString(content),
callback);
};
exports.toString = function toString(obj){
switch (typeof obj) {
case 'string':
case 'string':
return obj;
case 'object':
case 'object':
if (obj instanceof Array) {
obj.forEach(function (value, key){
obj[key] = toString(value);
@ -54,8 +54,8 @@ exports.copy = function(filename, callback){
fs.readFile('docs/src/templates/' + filename, function(err, content){
if (err) return callback.error(err);
fs.writeFile(
OUTPUT_DIR + filename,
content,
OUTPUT_DIR + filename,
content,
callback);
});
};

View file

@ -4,7 +4,7 @@ var browserSingleton;
* @ngdoc service
* @name angular.service.$browser
* @requires $log
*
*
* @description
* Represents the browser.
*/

View file

@ -67,12 +67,12 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#xhr
* @methodOf angular.service.$browser
*
*
* @param {string} method Requested method (get|post|put|delete|head|json)
* @param {string} url Requested url
* @param {string=} post Post data to send
* @param {string=} post Post data to send
* @param {function(number, string)} callback Function that will be called on response
*
*
* @description
* Send ajax request
*/
@ -113,7 +113,7 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#notifyWhenNoOutstandingRequests
* @methodOf angular.service.$browser
*
*
* @param {function()} callback Function that will be called when no outstanding request
*/
self.notifyWhenNoOutstandingRequests = function(callback) {
@ -144,12 +144,12 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#addPollFn
* @methodOf angular.service.$browser
*
*
* @param {function()} fn Poll function to add
*
*
* @description
* Adds a function to the list of functions that poller periodically executes
*
*
* @returns {function()} the added function
*/
self.addPollFn = function(fn) {
@ -162,10 +162,10 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#startPoller
* @methodOf angular.service.$browser
*
*
* @param {number} interval How often should browser call poll functions (ms)
* @param {function()} setTimeout Reference to a real or fake `setTimeout` function.
*
*
* @description
* Configures the poller to run in the specified intervals, using the specified
* setTimeout fn and kicks it off.
@ -180,15 +180,15 @@ function Browser(window, document, body, XHR, $log) {
//////////////////////////////////////////////////////////////
// URL API
//////////////////////////////////////////////////////////////
/**
* @workInProgress
* @ngdoc method
* @name angular.service.$browser#setUrl
* @methodOf angular.service.$browser
*
*
* @param {string} url New url
*
*
* @description
* Sets browser's url
*/
@ -204,10 +204,10 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#getUrl
* @methodOf angular.service.$browser
*
*
* @description
* Get current browser's url
*
*
* @returns {string} Browser's url
*/
self.getUrl = function() {
@ -261,10 +261,10 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#cookies
* @methodOf angular.service.$browser
*
*
* @param {string=} name Cookie name
* @param {string=} value Cokkie value
*
*
* @description
* The cookies method provides a 'private' low level access to browser cookies.
* It is not meant to be used directly, use the $cookie service instead.
@ -275,7 +275,7 @@ function Browser(window, document, body, XHR, $log) {
* <li>cookies(name, value) -> set name to value, if value is undefined delete the cookie</li>
* <li>cookies(name) -> the same as (name, undefined) == DELETES (no one calls it right now that way)</li>
* </ul>
*
*
* @returns {Object} Hash of all cookies (if called without any parameter)
*/
self.cookies = function (name, value) {
@ -342,7 +342,7 @@ function Browser(window, document, body, XHR, $log) {
// Misc API
//////////////////////////////////////////////////////////////
var hoverListener = noop;
/**
* @workInProgress
* @ngdoc method
@ -356,13 +356,13 @@ function Browser(window, document, body, XHR, $log) {
* occurs.
*/
self.hover = function(listener) { hoverListener = listener; };
/**
* @workInProgress
* @ngdoc method
* @name angular.service.$browser#bind
* @methodOf angular.service.$browser
*
*
* @description
* Register hover function to real browser
*/
@ -383,7 +383,7 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#addCss
* @methodOf angular.service.$browser
*
*
* @param {string} url Url to css file
* @description
* Adds a stylesheet tag to the head.
@ -402,10 +402,10 @@ function Browser(window, document, body, XHR, $log) {
* @ngdoc method
* @name angular.service.$browser#addJs
* @methodOf angular.service.$browser
*
*
* @param {string} url Url to js file
* @param {string=} dom_id Optional id for the script tag
*
* @param {string=} dom_id Optional id for the script tag
*
* @description
* Adds a script tag to the head.
*/

View file

@ -123,19 +123,19 @@ Compiler.prototype = {
};
},
/**
* @workInProgress
* @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
* 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
*
@ -164,7 +164,7 @@ Compiler.prototype = {
<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');

View file

@ -31,7 +31,7 @@ function createInjector(providerScope, providers, cache) {
* array of keys: returns an array of instances.
* function: look at $inject property of function to determine instances
* and then call the function with instances and `scope`. Any
* additional arguments (`args`) are appended to the function
* additional arguments (`args`) are appended to the function
* arguments.
* object: initialize eager providers and publish them the ones with publish here.
* none: same as object but use providerScope as place to publish.

View file

@ -74,18 +74,18 @@ angularTextMarkup('OPTION', function(text, textNode, parentElement){
* @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
* 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}}"/>
@ -101,8 +101,8 @@ angularTextMarkup('OPTION', function(text, textNode, parentElement){
* @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
* 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.
@ -111,7 +111,7 @@ angularTextMarkup('OPTION', function(text, textNode, parentElement){
* <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}}"/>

View file

@ -49,8 +49,8 @@ function lex(text, parseStringsForObjects){
}
} else if (is('(){}[].,;:')) {
tokens.push({
index:index,
text:ch,
index:index,
text:ch,
json:(was(':[,') && is('{[')) || is('}]:,')
});
if (is('{[')) json.unshift(ch);
@ -108,8 +108,8 @@ function lex(text, parseStringsForObjects){
end = end || index;
throw Error("Lexer Error: " + error + " at column" +
(isDefined(start) ?
"s " + start + "-" + index + " [" + text.substring(start, end) + "]" :
" " + end) +
"s " + start + "-" + index + " [" + text.substring(start, end) + "]" :
" " + end) +
" in expression [" + text + "].");
}
@ -157,8 +157,8 @@ function lex(text, parseStringsForObjects){
}
fn = OPERATORS[ident];
tokens.push({
index:start,
text:ident,
index:start,
text:ident,
json: fn,
fn:fn||extend(getterFn(ident), {
assign:function(self, value){
@ -167,7 +167,7 @@ function lex(text, parseStringsForObjects){
})
});
}
function readString(quote) {
var start = index;
index++;
@ -217,25 +217,25 @@ function lex(text, parseStringsForObjects){
function parser(text, json){
var ZERO = valueFn(0),
tokens = lex(text, json),
assignment = _assignment,
assignment = _assignment,
assignable = logicalOR,
functionCall = _functionCall,
fieldAccess = _fieldAccess,
objectIndex = _objectIndex,
filterChain = _filterChain,
functionIdent = _functionIdent,
functionCall = _functionCall,
fieldAccess = _fieldAccess,
objectIndex = _objectIndex,
filterChain = _filterChain,
functionIdent = _functionIdent,
pipeFunction = _pipeFunction;
if(json){
// The extra level of aliasing is here, just in case the lexer misses something, so that
// The extra level of aliasing is here, just in case the lexer misses something, so that
// we prevent any accidental execution in JSON.
assignment = logicalOR;
functionCall =
fieldAccess =
objectIndex =
functionCall =
fieldAccess =
objectIndex =
assignable =
filterChain =
functionIdent =
pipeFunction =
filterChain =
functionIdent =
pipeFunction =
function (){ throwError("is not valid json", {text:text, index:0}); };
}
return {
@ -368,7 +368,7 @@ function parser(text, json){
argFns.push(expression());
} else {
return valueFn({
format:invokeFn(formatter.format),
format:invokeFn(formatter.format),
parse:invokeFn(formatter.parse)
});
}

View file

@ -214,7 +214,7 @@ function decodeEntities(value) {
}
/**
* Escapes all potentially dangerous characters, so that the
* Escapes all potentially dangerous characters, so that the
* resulting string can be safely inserted into attribute or
* element text.
* @param value

View file

@ -3,7 +3,7 @@
*/
angular.scenario.output('json', function(context, runner) {
var model = new angular.scenario.ObjectModel(runner);
runner.on('RunnerEnd', function() {
context.text(angular.toJson(model.value));
});

View file

@ -11,16 +11,16 @@ function angularServiceInject(name, fn, inject, eager) {
* @workInProgress
* @ngdoc service
* @name angular.service.$window
*
*
* @description
* Is reference to the browser's <b>window</b> object. While <b>window</b>
* is globally available in JavaScript, it causes testability problems, because
* it is a global variable. In <b><angular/></b> we always refer to it through the
* $window service, so it may be overriden, removed or mocked for testing.
*
*
* All expressions are evaluated with respect to current scope so they don't
* suffer from window globality.
*
*
* @example
<input ng:init="greeting='Hello World!'" type="text" name="greeting" />
<button ng:click="$window.alert(greeting)">ALERT</button>
@ -32,7 +32,7 @@ angularServiceInject("$window", bind(window, identity, window), [], EAGER);
* @ngdoc service
* @name angular.service.$document
* @requires $window
*
*
* @description
* Reference to the browser window.document, but wrapped into angular.element().
*/
@ -45,7 +45,7 @@ angularServiceInject("$document", function(window){
* @ngdoc service
* @name angular.service.$location
* @requires $browser
*
*
* @property {string} href
* @property {string} protocol
* @property {string} host
@ -55,15 +55,15 @@ angularServiceInject("$document", function(window){
* @property {string} hash
* @property {string} hashPath
* @property {Object.<string|boolean>} hashSearch
*
*
* @description
* Parses the browser location url and makes it available to your application.
* Any changes to the url are reflected into $location service and changes to
* $location are reflected to url.
* Notice that using browser's forward/back buttons changes the $location.
*
*
* @example
<a href="#">clear hash</a> |
<a href="#">clear hash</a> |
<a href="#myPath?name=misko">test hash</a><br/>
<input type='text' name="$location.hash"/>
<pre>$location = {{$location}}</pre>
@ -91,7 +91,7 @@ angularServiceInject("$location", function($browser) {
* @ngdoc method
* @name angular.service.$location#update
* @methodOf angular.service.$location
*
*
* @description
* Update location object
* Does not immediately update the browser
@ -127,7 +127,7 @@ angularServiceInject("$location", function($browser) {
* @ngdoc method
* @name angular.service.$location#updateHash
* @methodOf angular.service.$location
*
*
* @description
* Update location hash part
* @see update()
@ -288,13 +288,13 @@ angularServiceInject("$location", function($browser) {
* @ngdoc service
* @name angular.service.$log
* @requires $window
*
*
* @description
* Is simple service for logging. Default implementation writes the message
* into the browser's console (if present).
*
*
* This is useful for debugging.
*
*
* @example
<p>Reload this page with open console, enter text and hit the log button...</p>
Message:
@ -311,46 +311,46 @@ angularServiceInject("$log", function($window){
* @ngdoc method
* @name angular.service.$log#log
* @methodOf angular.service.$log
*
*
* @description
* Write a log message
*/
log: consoleLog('log'),
/**
* @workInProgress
* @ngdoc method
* @name angular.service.$log#warn
* @methodOf angular.service.$log
*
*
* @description
* Write a warning message
*/
warn: consoleLog('warn'),
/**
* @workInProgress
* @ngdoc method
* @name angular.service.$log#info
* @methodOf angular.service.$log
*
*
* @description
* Write an information message
*/
info: consoleLog('info'),
/**
* @workInProgress
* @ngdoc method
* @name angular.service.$log#error
* @methodOf angular.service.$log
*
*
* @description
* Write an error message
*/
error: consoleLog('error')
};
function consoleLog(type) {
var console = $window.console || {};
var logFn = console[type] || console.log || noop;
@ -374,17 +374,17 @@ angularServiceInject("$log", function($window){
* @ngdoc service
* @name angular.service.$exceptionHandler
* @requires $log
*
*
* @description
* Any uncaught exception in <angular/> is delegated to this service.
* The default implementation simply delegates to $log.error which logs it into
* the browser console.
*
*
* When unit testing it is useful to have uncaught exceptions propagate
* to the test so the test will fail rather than silently log the exception
* to the browser console. For this purpose you can override this service with
* a simple rethrow.
*
* a simple rethrow.
*
* @example
*/
angularServiceInject('$exceptionHandler', function($log){
@ -459,9 +459,9 @@ angularServiceInject('$updateView', serviceUpdateViewFactory, ['$browser']);
* @name angular.service.$hover
* @requires $browser
* @requires $document
*
*
* @description
*
*
* @example
*/
angularServiceInject("$hover", function(browser, document) {
@ -514,11 +514,11 @@ angularServiceInject("$hover", function(browser, document) {
* @workInProgress
* @ngdoc service
* @name angular.service.$invalidWidgets
*
*
* @description
* Keeps references to all invalid widgets found during validation.
* Can be queried to find whether there are any invalid widgets currently displayed.
*
*
* @example
*/
angularServiceInject("$invalidWidgets", function(){
@ -608,45 +608,45 @@ function switchRouteMatcher(on, when, dstName) {
* @ngdoc service
* @name angular.service.$route
* @requires $location
*
*
* @property {Object} current Name of the current route
* @property {Array.<Object>} routes List of configured routes
*
*
* @description
* Watches $location.hashPath and tries to map the hash to an existing route
* definition. It is used for deep-linking URLs to controllers and views (HTML partials).
*
*
* $route is typically used in conjunction with {@link angular.widget.ng:view ng:view} widget.
*
*
* @example
<p>
This example shows how changing the URL hash causes the <tt>$route</tt>
to match a route against the URL, and the <tt>[[ng:include]]</tt> pulls in the partial.
Try changing the URL in the input box to see changes.
This example shows how changing the URL hash causes the <tt>$route</tt>
to match a route against the URL, and the <tt>[[ng:include]]</tt> pulls in the partial.
Try changing the URL in the input box to see changes.
</p>
<script>
angular.service('myApp', function($route) {
$route.when('/Book/:bookId', {template:'rsrc/book.html', controller:BookCntl});
$route.when('/Book/:bookId/ch/:chapterId', {template:'rsrc/chapter.html', controller:ChapterCntl});
$route.onChange(function() {
$route.current.scope.params = $route.current.params;
});
}, {$inject: ['$route']});
function BookCntl() {
this.name = "BookCntl";
}
function ChapterCntl() {
this.name = "ChapterCntl";
}
angular.service('myApp', function($route) {
$route.when('/Book/:bookId', {template:'rsrc/book.html', controller:BookCntl});
$route.when('/Book/:bookId/ch/:chapterId', {template:'rsrc/chapter.html', controller:ChapterCntl});
$route.onChange(function() {
$route.current.scope.params = $route.current.params;
});
}, {$inject: ['$route']});
function BookCntl() {
this.name = "BookCntl";
}
function ChapterCntl() {
this.name = "ChapterCntl";
}
</script>
Chose:
<a href="#/Book/Moby">Moby</a> |
<a href="#/Book/Moby/ch/1">Moby: Ch1</a> |
<a href="#/Book/Gatsby">Gatsby</a> |
Chose:
<a href="#/Book/Moby">Moby</a> |
<a href="#/Book/Moby/ch/1">Moby: Ch1</a> |
<a href="#/Book/Gatsby">Gatsby</a> |
<a href="#/Book/Gatsby/ch/4?key=value">Gatsby: Ch4</a><br/>
<input type="text" name="$location.hashPath" size="80" />
<pre>$location={{$location}}</pre>
@ -664,31 +664,31 @@ angularServiceInject('$route', function(location) {
dirty = 0,
$route = {
routes: routes,
/**
* @workInProgress
* @ngdoc method
* @name angular.service.$route#onChange
* @methodOf angular.service.$route
*
*
* @param {function()} fn Function that will be called on route change
*
*
* @description
* Register a handler function that will be called when route changes
*/
onChange: bind(onChange, onChange.push),
/**
* @workInProgress
* @ngdoc method
* @name angular.service.$route#when
* @methodOf angular.service.$route
*
*
* @param {string} path Route path (matched against $location.hash)
* @param {Object} params Mapping information to be assigned to `$route.current` on route
* match.
* @returns {Object} route object
*
*
* @description
* Add new route
*/
@ -732,9 +732,9 @@ angularServiceInject('$route', function(location) {
* @requires $browser
* @requires $xhr.error
* @requires $log
*
*
* @description
*
*
* @example
*/
angularServiceInject('$xhr', function($browser, $error, $log){
@ -773,9 +773,9 @@ angularServiceInject('$xhr', function($browser, $error, $log){
* @ngdoc service
* @name angular.service.$xhr.error
* @requires $log
*
*
* @description
*
*
* @example
*/
angularServiceInject('$xhr.error', function($log){
@ -791,9 +791,9 @@ angularServiceInject('$xhr.error', function($log){
* @requires $xhr
* @requires $xhr.error
* @requires $log
*
*
* @description
*
*
* @example
*/
angularServiceInject('$xhr.bulk', function($xhr, $error, $log){
@ -885,9 +885,9 @@ angularServiceInject('$defer', function($browser, $exceptionHandler, $updateView
* @ngdoc service
* @name angular.service.$xhr.cache
* @requires $xhr
*
*
* @description
*
*
* @example
*/
angularServiceInject('$xhr.cache', function($xhr, $defer, $log){
@ -942,7 +942,7 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $log){
* @requires $xhr
*
* @description
* Is a factory which creates a resource object which lets you interact with
* Is a factory which creates a resource object which lets you interact with
* <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" target="_blank">RESTful</a>
* server-side data sources.
* Resource object has action methods which provide high-level behaviors without
@ -1051,7 +1051,7 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $log){
{get:{method:'JSON', params:{visibility:'@self'}}, replies: {method:'JSON', params:{visibility:'@self', comments:'@comments'}}}
);
}
BuzzController.prototype = {
fetch: function() {
this.activities = this.Activity.get({userId:this.userId});
@ -1069,9 +1069,9 @@ angularServiceInject('$xhr.cache', function($xhr, $defer, $log){
<hr/>
<div ng:repeat="item in activities.data.items">
<h1 style="font-size: 15px;">
<img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
<a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
<a href ng:click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a>
<img src="{{item.actor.thumbnailUrl}}" style="max-height:30px;max-width:30px;"/>
<a href="{{item.actor.profileUrl}}">{{item.actor.name}}</a>
<a href ng:click="expandReplies(item)" style="float: right;">Expand replies: {{item.links.replies[0].count}}</a>
</h1>
{{item.object.content | html}}
<div ng:repeat="reply in item.replies.data.items" style="margin-left: 20px;">
@ -1091,13 +1091,13 @@ angularServiceInject('$resource', function($xhr){
* @ngdoc service
* @name angular.service.$cookies
* @requires $browser
*
*
* @description
* Provides read/write access to browser's cookies.
*
*
* Only a simple Object is exposed and by adding or removing properties to/from
* this object, new cookies are created/deleted at the end of current $eval.
*
*
* @example
*/
angularServiceInject('$cookies', function($browser) {
@ -1181,7 +1181,7 @@ angularServiceInject('$cookies', function($browser) {
* @ngdoc service
* @name angular.service.$cookieStore
* @requires $cookies
*
*
* @description
* Provides a key-value (string-object) storage, that is backed by session cookies.
* Objects put or retrieved from this storage are automatically serialized or
@ -1196,10 +1196,10 @@ angularServiceInject('$cookieStore', function($store) {
* @ngdoc method
* @name angular.service.$cookieStore#get
* @methodOf angular.service.$cookieStore
*
*
* @description
* Returns the value of given cookie key
*
*
* @param {string} key Id to use for lookup.
* @returns {Object} Deserialized cookie value.
*/
@ -1212,10 +1212,10 @@ angularServiceInject('$cookieStore', function($store) {
* @ngdoc method
* @name angular.service.$cookieStore#put
* @methodOf angular.service.$cookieStore
*
*
* @description
* Sets a value for given cookie key
*
*
* @param {string} key Id for the `value`.
* @param {Object} value Value to be stored.
*/
@ -1228,10 +1228,10 @@ angularServiceInject('$cookieStore', function($store) {
* @ngdoc method
* @name angular.service.$cookieStore#remove
* @methodOf angular.service.$cookieStore
*
*
* @description
* Remove given cookie
*
*
* @param {string} key Id of the key-value pair to delete.
*/
remove: function(key) {

View file

@ -7,32 +7,32 @@ extend(angularValidator, {
* @name angular.validator.regexp
* @description
* Use regexp validator to restrict the input to any Regular Expression.
*
*
* @param {string} value value to validate
* @param {string|regexp} expression regular expression.
* @param {string=} msg error message to display.
* @css ng-validation-error
*
*
* @example
* <script> function Cntl(){
* this.ssnRegExp = /^\d\d\d-\d\d-\d\d\d\d$/;
* this.ssnRegExp = /^\d\d\d-\d\d-\d\d\d\d$/;
* }
* </script>
* Enter valid SSN:
* <div ng:controller="Cntl">
* <input name="ssn" value="123-45-6789" ng:validate="regexp:ssnRegExp" >
* </div>
*
*
* @scenario
* it('should invalidate non ssn', function(){
* var textBox = element('.doc-example :input');
* expect(textBox.attr('className')).not().toMatch(/ng-validation-error/);
* expect(textBox.val()).toEqual('123-45-6789');
*
*
* input('ssn').enter('123-45-67890');
* expect(textBox.attr('className')).toMatch(/ng-validation-error/);
* });
*
*
*/
'regexp': function(value, regexp, msg) {
if (!value.match(regexp)) {
@ -48,38 +48,38 @@ extend(angularValidator, {
* @ngdoc validator
* @name angular.validator.number
* @description
* Use number validator to restrict the input to numbers with an
* Use number validator to restrict the input to numbers with an
* optional range. (See integer for whole numbers validator).
*
*
* @param {string} value value to validate
* @param {int=} [min=MIN_INT] minimum value.
* @param {int=} [max=MAX_INT] maximum value.
* @css ng-validation-error
*
*
* @example
* Enter number: <input name="n1" ng:validate="number" > <br>
* Enter number greater than 10: <input name="n2" ng:validate="number:10" > <br>
* Enter number between 100 and 200: <input name="n3" ng:validate="number:100:200" > <br>
*
*
* @scenario
* it('should invalidate number', function(){
* var n1 = element('.doc-example :input[name=n1]');
* expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
* input('n1').enter('1.x');
* expect(n1.attr('className')).toMatch(/ng-validation-error/);
*
*
* var n2 = element('.doc-example :input[name=n2]');
* expect(n2.attr('className')).not().toMatch(/ng-validation-error/);
* input('n2').enter('9');
* expect(n2.attr('className')).toMatch(/ng-validation-error/);
*
*
* var n3 = element('.doc-example :input[name=n3]');
* expect(n3.attr('className')).not().toMatch(/ng-validation-error/);
* input('n3').enter('201');
* expect(n3.attr('className')).toMatch(/ng-validation-error/);
*
*
* });
*
*
*/
'number': function(value, min, max) {
var num = 1 * value;
@ -101,36 +101,36 @@ extend(angularValidator, {
* @ngdoc validator
* @name angular.validator.integer
* @description
* Use number validator to restrict the input to integers with an
* Use number validator to restrict the input to integers with an
* optional range. (See integer for whole numbers validator).
*
*
* @param {string} value value to validate
* @param {int=} [min=MIN_INT] minimum value.
* @param {int=} [max=MAX_INT] maximum value.
* @css ng-validation-error
*
*
* @example
* Enter integer: <input name="n1" ng:validate="integer" > <br>
* Enter integer equal or greater than 10: <input name="n2" ng:validate="integer:10" > <br>
* Enter integer between 100 and 200 (inclusive): <input name="n3" ng:validate="integer:100:200" > <br>
*
*
* @scenario
* it('should invalidate integer', function(){
* var n1 = element('.doc-example :input[name=n1]');
* expect(n1.attr('className')).not().toMatch(/ng-validation-error/);
* input('n1').enter('1.1');
* expect(n1.attr('className')).toMatch(/ng-validation-error/);
*
*
* var n2 = element('.doc-example :input[name=n2]');
* expect(n2.attr('className')).not().toMatch(/ng-validation-error/);
* input('n2').enter('10.1');
* expect(n2.attr('className')).toMatch(/ng-validation-error/);
*
*
* var n3 = element('.doc-example :input[name=n3]');
* expect(n3.attr('className')).not().toMatch(/ng-validation-error/);
* input('n3').enter('100.1');
* expect(n3.attr('className')).toMatch(/ng-validation-error/);
*
*
* });
*/
'integer': function(value, min, max) {
@ -149,14 +149,14 @@ extend(angularValidator, {
* @description
* Use date validator to restrict the user input to a valid date
* in format in format MM/DD/YYYY.
*
*
* @param {string} value value to validate
* @css ng-validation-error
*
*
* @example
* Enter valid date:
* <input name="text" value="1/1/2009" ng:validate="date" >
*
*
* @scenario
* it('should invalidate date', function(){
* var n1 = element('.doc-example :input');
@ -164,7 +164,7 @@ extend(angularValidator, {
* input('text').enter('123/123/123');
* expect(n1.attr('className')).toMatch(/ng-validation-error/);
* });
*
*
*/
'date': function(value) {
var fields = /^(\d\d?)\/(\d\d?)\/(\d\d\d\d)$/.exec(value);
@ -182,14 +182,14 @@ extend(angularValidator, {
* @name angular.validator.email
* @description
* Use email validator if you wist to restrict the user input to a valid email.
*
*
* @param {string} value value to validate
* @css ng-validation-error
*
*
* @example
* Enter valid email:
* <input name="text" ng:validate="email" value="me@example.com">
*
*
* @scenario
* it('should invalidate email', function(){
* var n1 = element('.doc-example :input');
@ -197,7 +197,7 @@ extend(angularValidator, {
* input('text').enter('a@b.c');
* expect(n1.attr('className')).toMatch(/ng-validation-error/);
* });
*
*
*/
'email': function(value) {
if (value.match(/^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$/)) {
@ -212,14 +212,14 @@ extend(angularValidator, {
* @name angular.validator.phone
* @description
* Use phone validator to restrict the input phone numbers.
*
*
* @param {string} value value to validate
* @css ng-validation-error
*
*
* @example
* Enter valid phone number:
* <input name="text" value="1(234)567-8901" ng:validate="phone" >
*
*
* @scenario
* it('should invalidate phone', function(){
* var n1 = element('.doc-example :input');
@ -227,7 +227,7 @@ extend(angularValidator, {
* input('text').enter('+12345678');
* expect(n1.attr('className')).toMatch(/ng-validation-error/);
* });
*
*
*/
'phone': function(value) {
if (value.match(/^1\(\d\d\d\)\d\d\d-\d\d\d\d$/)) {
@ -245,14 +245,14 @@ extend(angularValidator, {
* @name angular.validator.url
* @description
* Use phone validator to restrict the input URLs.
*
*
* @param {string} value value to validate
* @css ng-validation-error
*
*
* @example
* Enter valid phone number:
* <input name="text" value="http://example.com/abc.html" size="40" ng:validate="url" >
*
*
* @scenario
* it('should invalidate url', function(){
* var n1 = element('.doc-example :input');
@ -260,7 +260,7 @@ extend(angularValidator, {
* input('text').enter('abc://server/path');
* expect(n1.attr('className')).toMatch(/ng-validation-error/);
* });
*
*
*/
'url': function(value) {
if (value.match(/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/)) {
@ -275,15 +275,15 @@ extend(angularValidator, {
* @name angular.validator.json
* @description
* Use json validator if you wish to restrict the user input to a valid JSON.
*
*
* @param {string} value value to validate
* @css ng-validation-error
*
*
* @example
* <textarea name="json" cols="60" rows="5" ng:validate="json">
* {name:'abc'}
* </textarea>
*
*
* @scenario
* it('should invalidate json', function(){
* var n1 = element('.doc-example :input');
@ -291,7 +291,7 @@ extend(angularValidator, {
* input('json').enter('{name}');
* expect(n1.attr('className')).toMatch(/ng-validation-error/);
* });
*
*
*/
'json': function(value) {
try {
@ -307,36 +307,36 @@ extend(angularValidator, {
* @ngdoc validator
* @name angular.validator.asynchronous
* @description
* Use asynchronous validator if the validation can not be computed
* immediately, but is provided through a callback. The widget
* automatically shows a spinning indicator while the validity of
* Use asynchronous validator if the validation can not be computed
* immediately, but is provided through a callback. The widget
* automatically shows a spinning indicator while the validity of
* the widget is computed. This validator caches the result.
*
*
* @param {string} value value to validate
* @param {function(inputToValidate,validationDone)} validate function to call to validate the state
* of the input.
* @param {function(data)=} [update=noop] function to call when state of the
* @param {function(data)=} [update=noop] function to call when state of the
* validator changes
*
*
* @paramDescription
* The `validate` function (specified by you) is called as
* The `validate` function (specified by you) is called as
* `validate(inputToValidate, validationDone)`:
*
*
* * `inputToValidate`: value of the input box.
* * `validationDone`: `function(error, data){...}`
* * `error`: error text to display if validation fails
* * `data`: data object to pass to update function
*
*
* The `update` function is optionally specified by you and is
* called by <angular/> on input change. Since the
* asynchronous validator caches the results, the update
* function can be called without a call to `validate`
* called by <angular/> on input change. Since the
* asynchronous validator caches the results, the update
* function can be called without a call to `validate`
* function. The function is called as `update(data)`:
*
*
* * `data`: data object as passed from validate function
*
*
* @css ng-input-indicator-wait, ng-validation-error
*
*
* @example
* <script>
* function MyCntl(){
@ -351,23 +351,23 @@ extend(angularValidator, {
* <div ng:controller="MyCntl">
* <input name="text" ng:validate="asynchronous:myValidator">
* </div>
*
*
* @scenario
* it('should change color in delayed way', function(){
* var textBox = element('.doc-example :input');
* expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/);
* expect(textBox.attr('className')).not().toMatch(/ng-validation-error/);
*
*
* input('text').enter('X');
* expect(textBox.attr('className')).toMatch(/ng-input-indicator-wait/);
*
*
* pause(.6);
*
*
* expect(textBox.attr('className')).not().toMatch(/ng-input-indicator-wait/);
* expect(textBox.attr('className')).toMatch(/ng-validation-error/);
*
*
* });
*
*
*/
/*
* cache is attached to the element

View file

@ -312,24 +312,24 @@ describe('angular service', function() {
var scope = createScope();
angular.service('fake', function() { return 'old'; });
angular.service('fake', function() { return 'new'; });
expect(scope.$service('fake')).toEqual('new');
});
it('should not preserve properties on override', function() {
angular.service('fake', {$one: true}, {$two: true}, {three: true});
var result = angular.service('fake', {$four: true});
expect(result.$one).toBeUndefined();
expect(result.$two).toBeUndefined();
expect(result.three).toBeUndefined();
expect(result.$four).toBe(true);
});
it('should not preserve non-angular properties on override', function() {
angular.service('fake', {one: true}, {two: true});
var result = angular.service('fake', {third: true});
expect(result.one).not.toBeDefined();
expect(result.two).not.toBeDefined();
expect(result.third).toBeTruthy();

View file

@ -1,16 +1,16 @@
describe('Binder', function(){
beforeEach(function(){
var self = this;
this.compile = function(html, initialScope, parent) {
var compiler = new Compiler(angularTextMarkup, angularAttrMarkup, angularDirective, angularWidget);
if (self.element) dealoc(self.element);
var element = self.element = jqLite(html);
var scope = compiler.compile(element)(element);
if (parent) parent.append(element);
extend(scope, initialScope);
scope.$init();
return {node:element, scope:scope};
@ -19,48 +19,48 @@ describe('Binder', function(){
return sortedHtml(this.compile(content).node);
};
});
afterEach(function(){
if (this.element && this.element.dealoc) {
this.element.dealoc();
}
});
it('ChangingTextfieldUpdatesModel', function(){
var state = this.compile('<input type="text" name="model.price" value="abc">', {model:{}});
state.scope.$eval();
assertEquals('abc', state.scope.model.price);
});
it('ChangingTextareaUpdatesModel', function(){
var c = this.compile('<textarea name="model.note">abc</textarea>');
c.scope.$eval();
assertEquals(c.scope.model.note, 'abc');
});
it('ChangingRadioUpdatesModel', function(){
var c = this.compile('<input type="radio" name="model.price" value="A" checked>' +
'<input type="radio" name="model.price" value="B">');
c.scope.$eval();
assertEquals(c.scope.model.price, 'A');
});
it('ChangingCheckboxUpdatesModel', function(){
var form = this.compile('<input type="checkbox" name="model.price" value="true" checked ng:format="boolean"/>');
assertEquals(true, form.scope.model.price);
});
it('BindUpdate', function(){
var c = this.compile('<div ng:eval="a=123"/>');
assertEquals(123, c.scope.$get('a'));
});
it('ChangingSelectNonSelectedUpdatesModel', function(){
var form = this.compile('<select name="model.price"><option value="A">A</option><option value="B">B</option></select>');
assertEquals('A', form.scope.model.price);
});
it('ChangingMultiselectUpdatesModel', function(){
var form = this.compile('<select name="Invoice.options" multiple="multiple">' +
'<option value="A" selected>Gift wrap</option>' +
@ -69,35 +69,35 @@ describe('Binder', function(){
'</select>');
assertJsonEquals(["A", "B"], form.scope.$get('Invoice').options);
});
it('ChangingSelectSelectedUpdatesModel', function(){
var form = this.compile('<select name="model.price"><option>A</option><option selected value="b">B</option></select>');
assertEquals(form.scope.model.price, 'b');
});
it('ExecuteInitialization', function(){
var c = this.compile('<div ng:init="a=123">');
assertEquals(c.scope.$get('a'), 123);
});
it('ExecuteInitializationStatements', function(){
var c = this.compile('<div ng:init="a=123;b=345">');
assertEquals(c.scope.$get('a'), 123);
assertEquals(c.scope.$get('b'), 345);
});
it('ApplyTextBindings', function(){
var form = this.compile('<div ng:bind="model.a">x</div>');
form.scope.$set('model', {a:123});
form.scope.$eval();
assertEquals('123', form.node.text());
});
it('ReplaceBindingInTextWithSpan', function(){
assertEquals(this.compileToHtml("<b>a{{b}}c</b>"), '<b>a<span ng:bind="b"></span>c</b>');
assertEquals(this.compileToHtml("<b>{{b}}</b>"), '<b><span ng:bind="b"></span></b>');
});
it('BindingSpaceConfusesIE', function(){
if (!msie) return;
var span = document.createElement("span");
@ -110,7 +110,7 @@ describe('Binder', function(){
'<b><span ng:bind="A"></span><span>'+nbsp+'x </span><span ng:bind="B"></span><span>'+nbsp+'(</span><span ng:bind="C"></span>)</b>',
this.compileToHtml("<b>{{A}} x {{B}} ({{C}})</b>"));
});
it('BindingOfAttributes', function(){
var c = this.compile("<a href='http://s/a{{b}}c' foo='x'></a>");
var attrbinding = c.node.attr("ng:bind-attr");
@ -118,7 +118,7 @@ describe('Binder', function(){
assertEquals("http://s/a{{b}}c", decodeURI(bindings.href));
assertTrue(!bindings.foo);
});
it('MarkMultipleAttributes', function(){
var c = this.compile('<a href="http://s/a{{b}}c" foo="{{d}}"></a>');
var attrbinding = c.node.attr("ng:bind-attr");
@ -126,20 +126,20 @@ describe('Binder', function(){
assertEquals(bindings.foo, "{{d}}");
assertEquals(decodeURI(bindings.href), "http://s/a{{b}}c");
});
it('AttributesNoneBound', function(){
var c = this.compile("<a href='abc' foo='def'></a>");
var a = c.node;
assertEquals(a[0].nodeName, "A");
assertTrue(!a.attr("ng:bind-attr"));
});
it('ExistingAttrbindingIsAppended', function(){
var c = this.compile("<a href='http://s/{{abc}}' ng:bind-attr='{\"b\":\"{{def}}\"}'></a>");
var a = c.node;
assertEquals('{"b":"{{def}}","href":"http://s/{{abc}}"}', a.attr('ng:bind-attr'));
});
it('AttributesAreEvaluated', function(){
var c = this.compile('<a ng:bind-attr=\'{"a":"a", "b":"a+b={{a+b}}"}\'></a>');
var binder = c.binder, form = c.node;
@ -149,7 +149,7 @@ describe('Binder', function(){
assertEquals(a.attr('a'), 'a');
assertEquals(a.attr('b'), 'a+b=3');
});
it('InputTypeButtonActionExecutesInScope', function(){
var savedCalled = false;
var c = this.compile('<input type="button" ng:click="person.save()" value="Apply">');
@ -159,7 +159,7 @@ describe('Binder', function(){
browserTrigger(c.node, 'click');
assertTrue(savedCalled);
});
it('InputTypeButtonActionExecutesInScope2', function(){
var log = "";
var c = this.compile('<input type="image" ng:click="action()">');
@ -170,7 +170,7 @@ describe('Binder', function(){
browserTrigger(c.node, 'click');
expect(log).toEqual('click;');
});
it('ButtonElementActionExecutesInScope', function(){
var savedCalled = false;
var c = this.compile('<button ng:click="person.save()">Apply</button>');
@ -180,20 +180,20 @@ describe('Binder', function(){
browserTrigger(c.node, 'click');
assertTrue(savedCalled);
});
it('RepeaterUpdateBindings', function(){
var a = this.compile('<ul><LI ng:repeat="item in model.items" ng:bind="item.a"/></ul>');
var form = a.node;
var items = [{a:"A"}, {a:"B"}];
a.scope.$set('model', {items:items});
a.scope.$eval();
assertEquals('<ul>' +
'<#comment></#comment>' +
'<li ng:bind="item.a" ng:repeat-index="0">A</li>' +
'<li ng:bind="item.a" ng:repeat-index="1">B</li>' +
'</ul>', sortedHtml(form));
items.unshift({a:'C'});
a.scope.$eval();
assertEquals('<ul>' +
@ -202,7 +202,7 @@ describe('Binder', function(){
'<li ng:bind="item.a" ng:repeat-index="1">A</li>' +
'<li ng:bind="item.a" ng:repeat-index="2">B</li>' +
'</ul>', sortedHtml(form));
items.shift();
a.scope.$eval();
assertEquals('<ul>' +
@ -210,12 +210,12 @@ describe('Binder', function(){
'<li ng:bind="item.a" ng:repeat-index="0">A</li>' +
'<li ng:bind="item.a" ng:repeat-index="1">B</li>' +
'</ul>', sortedHtml(form));
items.shift();
items.shift();
a.scope.$eval();
});
it('RepeaterContentDoesNotBind', function(){
var a = this.compile('<ul><LI ng:repeat="item in model.items"><span ng:bind="item.a"></span></li></ul>');
a.scope.$set('model', {items:[{a:"A"}]});
@ -225,18 +225,18 @@ describe('Binder', function(){
'<li ng:repeat-index="0"><span ng:bind="item.a">A</span></li>' +
'</ul>', sortedHtml(a.node));
});
it('ExpandEntityTag', function(){
assertEquals(
'<div ng-entity="Person" ng:watch="$anchor.a:1"></div>',
this.compileToHtml('<div ng-entity="Person" ng:watch="$anchor.a:1"/>'));
});
it('DoNotOverwriteCustomAction', function(){
var html = this.compileToHtml('<input type="submit" value="Save" action="foo();">');
assertTrue(html.indexOf('action="foo();"') > 0 );
});
it('RepeaterAdd', function(){
var c = this.compile('<div><input type="text" name="item.x" ng:repeat="item in items"></div>');
var doc = c.node;
@ -246,81 +246,81 @@ describe('Binder', function(){
var second = childNode(c.node, 2);
assertEquals('a', first.val());
assertEquals('b', second.val());
first.val('ABC');
browserTrigger(first, 'keydown');
c.scope.$service('$browser').defer.flush();
assertEquals(c.scope.items[0].x, 'ABC');
});
it('ItShouldRemoveExtraChildrenWhenIteratingOverHash', function(){
var c = this.compile('<div><div ng:repeat="i in items">{{i}}</div></div>');
var items = {};
c.scope.$set("items", items);
c.scope.$eval();
expect(c.node[0].childNodes.length - 1).toEqual(0);
items.name = "misko";
c.scope.$eval();
expect(c.node[0].childNodes.length - 1).toEqual(1);
delete items.name;
c.scope.$eval();
expect(c.node[0].childNodes.length - 1).toEqual(0);
});
it('IfTextBindingThrowsErrorDecorateTheSpan', function(){
var a = this.compile('<div>{{error.throw()}}</div>');
var doc = a.node;
a.scope.$set('error.throw', function(){throw "ErrorMsg1";});
a.scope.$eval();
var span = childNode(doc, 0);
assertTrue(span.hasClass('ng-exception'));
assertTrue(!!span.text().match(/ErrorMsg1/));
assertTrue(!!span.attr('ng-exception').match(/ErrorMsg1/));
a.scope.$set('error.throw', function(){throw "MyError";});
a.scope.$eval();
span = childNode(doc, 0);
assertTrue(span.hasClass('ng-exception'));
assertTrue(span.text(), span.text().match('MyError') !== null);
assertEquals('MyError', span.attr('ng-exception'));
a.scope.$set('error.throw', function(){return "ok";});
a.scope.$eval();
assertFalse(span.hasClass('ng-exception'));
assertEquals('ok', span.text());
assertEquals(null, span.attr('ng-exception'));
});
it('IfAttrBindingThrowsErrorDecorateTheAttribute', function(){
var a = this.compile('<div attr="before {{error.throw()}} after"></div>');
var doc = a.node;
a.scope.$set('error.throw', function(){throw "ErrorMsg";});
a.scope.$eval();
assertTrue('ng-exception', doc.hasClass('ng-exception'));
assertEquals('"ErrorMsg"', doc.attr('ng-exception'));
assertEquals('before "ErrorMsg" after', doc.attr('attr'));
a.scope.$set('error.throw', function(){ return 'X';});
a.scope.$eval();
assertFalse('!ng-exception', doc.hasClass('ng-exception'));
assertEquals('before X after', doc.attr('attr'));
assertEquals(null, doc.attr('ng-exception'));
});
it('NestedRepeater', function(){
var a = this.compile('<div><div ng:repeat="m in model" name="{{m.name}}">' +
'<ul name="{{i}}" ng:repeat="i in m.item"></ul>' +
'</div></div>');
a.scope.$set('model', [{name:'a', item:['a1', 'a2']}, {name:'b', item:['b1', 'b2']}]);
a.scope.$eval();
assertEquals('<div>'+
'<#comment></#comment>'+
'<div name="a" ng:bind-attr="{"name":"{{m.name}}"}" ng:repeat-index="0">'+
@ -334,82 +334,82 @@ describe('Binder', function(){
'<ul name="b2" ng:bind-attr="{"name":"{{i}}"}" ng:repeat-index="1"></ul>'+
'</div></div>', sortedHtml(a.node));
});
it('HideBindingExpression', function(){
var a = this.compile('<div ng:hide="hidden == 3"/>');
a.scope.$set('hidden', 3);
a.scope.$eval();
assertHidden(a.node);
a.scope.$set('hidden', 2);
a.scope.$eval();
assertVisible(a.node);
});
it('HideBinding', function(){
var c = this.compile('<div ng:hide="hidden"/>');
c.scope.$set('hidden', 'true');
c.scope.$eval();
assertHidden(c.node);
c.scope.$set('hidden', 'false');
c.scope.$eval();
assertVisible(c.node);
c.scope.$set('hidden', '');
c.scope.$eval();
assertVisible(c.node);
});
it('ShowBinding', function(){
var c = this.compile('<div ng:show="show"/>');
c.scope.$set('show', 'true');
c.scope.$eval();
assertVisible(c.node);
c.scope.$set('show', 'false');
c.scope.$eval();
assertHidden(c.node);
c.scope.$set('show', '');
c.scope.$eval();
assertHidden(c.node);
});
it('BindClassUndefined', function(){
var doc = this.compile('<div ng:class="undefined"/>');
doc.scope.$eval();
assertEquals(
'<div class="undefined" ng:class="undefined"></div>',
sortedHtml(doc.node));
});
it('BindClass', function(){
var c = this.compile('<div ng:class="class"/>');
c.scope.$set('class', 'testClass');
c.scope.$eval();
assertEquals('<div class="testClass" ng:class="class"></div>', sortedHtml(c.node));
c.scope.$set('class', ['a', 'b']);
c.scope.$eval();
assertEquals('<div class="a b" ng:class="class"></div>', sortedHtml(c.node));
});
it('BindClassEvenOdd', function(){
var x = this.compile('<div><div ng:repeat="i in [0,1]" ng:class-even="\'e\'" ng:class-odd="\'o\'"/></div>');
x.scope.$eval();
@ -423,19 +423,19 @@ describe('Binder', function(){
'<div class="e" ng:class-even="\'e\'" ng:class-odd="\'o\'" ng:repeat-index="1"></div></div>',
sortedHtml(x.node));
});
it('BindStyle', function(){
var c = this.compile('<div ng:style="style"/>');
c.scope.$eval('style={color:"red"}');
c.scope.$eval();
assertEquals("red", c.node.css('color'));
c.scope.$eval('style={}');
c.scope.$eval();
});
it('ActionOnAHrefThrowsError', function(){
var model = {books:[]};
var c = this.compile('<a ng:click="action()">Add Phone</a>', model);
@ -447,14 +447,14 @@ describe('Binder', function(){
var error = input.attr('ng-exception');
assertTrue(!!error.match(/MyError/));
assertTrue("should have an error class", input.hasClass('ng-exception'));
// TODO: I think that exception should never get cleared so this portion of test makes no sense
//c.scope.action = noop;
//browserTrigger(input, 'click');
//dump(input.attr('ng-error'));
//assertFalse('error class should be cleared', input.hasClass('ng-exception'));
});
it('ShoulIgnoreVbNonBindable', function(){
var c = this.compile("<div>{{a}}" +
"<div ng:non-bindable>{{a}}</div>" +
@ -464,31 +464,31 @@ describe('Binder', function(){
c.scope.$eval();
assertEquals('123{{a}}{{b}}{{c}}', c.node.text());
});
it('OptionShouldUpdateParentToGetProperBinding', function(){
var c = this.compile('<select name="s"><option ng:repeat="i in [0,1]" value="{{i}}" ng:bind="i"></option></select>');
c.scope.$set('s', 1);
c.scope.$eval();
assertEquals(1, c.node[0].selectedIndex);
});
it('RepeaterShouldBindInputsDefaults', function () {
var c = this.compile('<div><input value="123" name="item.name" ng:repeat="item in items"></div>');
c.scope.$set('items', [{}, {name:'misko'}]);
c.scope.$eval();
assertEquals("123", c.scope.$eval('items[0].name'));
assertEquals("misko", c.scope.$eval('items[1].name'));
});
it('ShouldTemplateBindPreElements', function () {
var c = this.compile('<pre>Hello {{name}}!</pre>');
c.scope.$set("name", "World");
c.scope.$eval();
assertEquals('<pre ng:bind-template="Hello {{name}}!">Hello World!</pre>', sortedHtml(c.node));
});
it('FillInOptionValueWhenMissing', function(){
var c = this.compile(
'<select><option selected="true">{{a}}</option><option value="">{{b}}</option><option>C</option></select>');
@ -498,17 +498,17 @@ describe('Binder', function(){
var optionA = childNode(c.node, 0);
var optionB = childNode(c.node, 1);
var optionC = childNode(c.node, 2);
expect(optionA.attr('value')).toEqual('A');
expect(optionA.text()).toEqual('A');
expect(optionB.attr('value')).toEqual('');
expect(optionB.text()).toEqual('B');
expect(optionC.attr('value')).toEqual('C');
expect(optionC.text()).toEqual('C');
});
it('ValidateForm', function(){
var c = this.compile('<div><input name="name" ng:required>' +
'<div ng:repeat="item in items"><input name="item.name" ng:required/></div></div>',
@ -517,39 +517,39 @@ describe('Binder', function(){
c.scope.$set("items", items);
c.scope.$eval();
assertEquals(3, c.scope.$service('$invalidWidgets').length);
c.scope.$set('name', '');
c.scope.$eval();
assertEquals(3, c.scope.$service('$invalidWidgets').length);
c.scope.$set('name', ' ');
c.scope.$eval();
assertEquals(3, c.scope.$service('$invalidWidgets').length);
c.scope.$set('name', 'abc');
c.scope.$eval();
assertEquals(2, c.scope.$service('$invalidWidgets').length);
items[0].name = 'abc';
c.scope.$eval();
assertEquals(1, c.scope.$service('$invalidWidgets').length);
items[1].name = 'abc';
c.scope.$eval();
assertEquals(0, c.scope.$service('$invalidWidgets').length);
});
it('ValidateOnlyVisibleItems', function(){
var c = this.compile('<div><input name="name" ng:required><input ng:show="show" name="name" ng:required></div>', undefined, jqLite(document.body));
c.scope.$set("show", true);
c.scope.$eval();
assertEquals(2, c.scope.$service('$invalidWidgets').length);
c.scope.$set("show", false);
c.scope.$eval();
assertEquals(1, c.scope.$service('$invalidWidgets').visible());
});
it('DeleteAttributeIfEvaluatesFalse', function(){
var c = this.compile('<div>' +
'<input name="a0" ng:bind-attr="{disabled:\'{{true}}\'}"><input name="a1" ng:bind-attr="{disabled:\'{{false}}\'}">' +
@ -560,7 +560,7 @@ describe('Binder', function(){
var child = childNode(c.node, index);
assertEquals(sortedHtml(child), disabled, !!child.attr('disabled'));
}
assertChild(0, true);
assertChild(1, false);
assertChild(2, true);
@ -568,41 +568,41 @@ describe('Binder', function(){
assertChild(4, true);
assertChild(5, false);
});
it('ItShouldDisplayErrorWhenActionIsSyntacticlyIncorect', function(){
var c = this.compile('<div>' +
'<input type="button" ng:click="greeting=\'ABC\'"/>' +
'<input type="button" ng:click=":garbage:"/></div>');
var first = jqLite(c.node[0].childNodes[0]);
var second = jqLite(c.node[0].childNodes[1]);
browserTrigger(first, 'click');
assertEquals("ABC", c.scope.greeting);
browserTrigger(second, 'click');
assertTrue(second.hasClass("ng-exception"));
});
it('ItShouldSelectTheCorrectRadioBox', function(){
var c = this.compile('<div>' +
'<input type="radio" name="sex" value="female"/>' +
'<input type="radio" name="sex" value="male"/></div>');
var female = jqLite(c.node[0].childNodes[0]);
var male = jqLite(c.node[0].childNodes[1]);
browserTrigger(female);
assertEquals("female", c.scope.sex);
assertEquals(true, female[0].checked);
assertEquals(false, male[0].checked);
assertEquals("female", female.val());
browserTrigger(male);
assertEquals("male", c.scope.sex);
assertEquals(false, female[0].checked);
assertEquals(true, male[0].checked);
assertEquals("male", male.val());
});
it('ItShouldListenOnRightScope', function(){
var c = this.compile(
'<ul ng:init="counter=0; gCounter=0" ng:watch="w:counter=counter+1">' +
@ -610,13 +610,13 @@ describe('Binder', function(){
c.scope.$eval();
assertEquals(1, c.scope.$get("counter"));
assertEquals(7, c.scope.$get("gCounter"));
c.scope.$set("w", "something");
c.scope.$eval();
assertEquals(2, c.scope.$get("counter"));
assertEquals(14, c.scope.$get("gCounter"));
});
it('ItShouldRepeatOnHashes', function(){
var x = this.compile('<ul><li ng:repeat="(k,v) in {a:0,b:1}" ng:bind=\"k + v\"></li></ul>');
x.scope.$eval();
@ -627,7 +627,7 @@ describe('Binder', function(){
'</ul>',
sortedHtml(x.node));
});
it('ItShouldFireChangeListenersBeforeUpdate', function(){
var x = this.compile('<div ng:bind="name"></div>');
x.scope.$set("name", "");
@ -639,19 +639,19 @@ describe('Binder', function(){
'<div ng:bind="name">123</div>',
sortedHtml(x.node));
});
it('ItShouldHandleMultilineBindings', function(){
var x = this.compile('<div>{{\n 1 \n + \n 2 \n}}</div>');
x.scope.$eval();
assertEquals("3", x.node.text());
});
it('ItBindHiddenInputFields', function(){
var x = this.compile('<input type="hidden" name="myName" value="abc" />');
x.scope.$eval();
assertEquals("abc", x.scope.$get("myName"));
});
it('ItShouldUseFormaterForText', function(){
var x = this.compile('<input name="a" ng:format="list" value="a,b">');
x.scope.$eval();
@ -665,4 +665,4 @@ describe('Binder', function(){
assertEquals('1, 2, 3', input[0].value);
});
});
});

View file

@ -32,7 +32,7 @@ describe('compiler', function(){
return scope;
};
});
afterEach(function(){
dealoc(scope);
});

View file

@ -1,17 +1,17 @@
describe('filter', function() {
var filter = angular.filter;
it('should called the filter when evaluating expression', function() {
var scope = createScope();
filter.fakeFilter = function(){};
spyOn(filter, 'fakeFilter');
scope.$eval('10|fakeFilter');
expect(filter.fakeFilter).toHaveBeenCalledWith(10);
delete filter['fakeFilter'];
});
it('should call filter on scope context', function() {
var scope = createScope();
scope.name = 'misko';
@ -19,7 +19,7 @@ describe('filter', function() {
expect(this.name).toEqual('misko');
};
spyOn(filter, 'fakeFilter').andCallThrough();
scope.$eval('10|fakeFilter');
expect(filter.fakeFilter).toHaveBeenCalled();
delete filter['fakeFilter'];
@ -39,7 +39,7 @@ describe('filter', function() {
expect(html.hasClass('ng-format-negative')).toBeFalsy();
});
});
describe('number', function() {
it('should do basic filter', function() {
var context = {jqElement:jqLite('<span/>')};

View file

@ -33,13 +33,13 @@ describe("formatter", function(){
assertEquals('a', angular.formatter.trim.format(" a "));
assertEquals('a', angular.formatter.trim.parse(' a '));
});
describe('json', function(){
it('should treat empty string as null', function(){
expect(angular.formatter.json.parse('')).toEqual(null);
});
});
describe('index', function(){
it('should parse an object from array', function(){
expect(angular.formatter.index.parse('1', ['A', 'B', 'C'])).toEqual('B');

View file

@ -58,7 +58,7 @@ describe('parser', function() {
expect(tokens[i].text).toEqual('undefined');
expect(undefined).toEqual(tokens[i].fn());
});
it('should tokenize quoted string', function() {
var str = "['\\'', \"\\\"\"]";
var tokens = lex(str);
@ -134,7 +134,7 @@ describe('parser', function() {
expect(function() {
lex("0.5E-");
}).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-].'));
expect(function() {
lex("0.5E-A");
}).toThrow(new Error('Lexer Error: Invalid exponent at column 4 in expression [0.5E-A].'));
@ -151,7 +151,7 @@ describe('parser', function() {
}).toThrow(new Error("Lexer Error: Invalid unicode escape [\\u1''b] at column 2 in expression ['\\u1''bla']."));
});
});
var scope;
beforeEach(function () {
scope = createScope();
@ -201,7 +201,7 @@ describe('parser', function() {
expect(function() {
scope.$eval("1|nonExistant");
}).toThrow(new Error("Parse Error: Token 'nonExistant' should be a function at column 3 of expression [1|nonExistant] starting at [nonExistant]."));
scope.$set('offset', 3);
expect(scope.$eval("'abcd'|upper._case")).toEqual("ABCD");
expect(scope.$eval("'abcd'|substring:1:offset")).toEqual("bc");
@ -298,7 +298,7 @@ describe('parser', function() {
scope.$set("obj", new C());
expect(scope.$eval("obj.getA()")).toEqual(123);
});
it('should evaluate methods in correct context (this) in argument', function() {
var C = function () {
this.a = 123;
@ -388,7 +388,7 @@ describe('parser', function() {
expect(scope.$eval("a=undefined")).not.toBeDefined();
expect(scope.$get("a")).not.toBeDefined();
});
it('should allow assignment after array dereference', function(){
scope = angular.scope();
scope.obj = [{}];
@ -396,21 +396,21 @@ describe('parser', function() {
expect(scope.obj.name).toBeUndefined();
expect(scope.obj[0].name).toEqual(1);
});
describe('formatter', function(){
it('should return no argument function', function() {
var noop = parser('noop').formatter()();
expect(noop.format(null, 'abc')).toEqual('abc');
expect(noop.parse(null, '123')).toEqual('123');
});
it('should delegate arguments', function(){
var index = parser('index:objs').formatter()();
expect(index.format({objs:['A','B']}, 'B')).toEqual('1');
expect(index.parse({objs:['A','B']}, '1')).toEqual('B');
});
});
describe('assignable', function(){
it('should expose assignment function', function(){
var fn = parser('a').assignable();
@ -420,5 +420,5 @@ describe('parser', function() {
expect(scope).toEqual({a:123});
});
});
});

View file

@ -1,14 +1,14 @@
describe("ScenarioSpec: Compilation", function(){
var scope;
beforeEach(function(){
scope = null;
});
afterEach(function(){
dealoc(scope);
});
describe('compilation', function(){
it("should compile dom node and return scope", function(){
var node = jqLite('<div ng:init="a=1">{{b=a+1}}</div>')[0];
@ -17,18 +17,18 @@ describe("ScenarioSpec: Compilation", function(){
expect(scope.a).toEqual(1);
expect(scope.b).toEqual(2);
});
it("should compile jQuery node and return scope", function(){
scope = compile(jqLite('<div>{{a=123}}</div>')).$init();
expect(jqLite(scope.$element).text()).toEqual('123');
});
it("should compile text node and return scope", function(){
scope = compile('<div>{{a=123}}</div>').$init();
expect(jqLite(scope.$element).text()).toEqual('123');
});
});
describe('scope', function(){
it("should have set, get, eval, $init, updateView methods", function(){
scope = compile('<div>{{a}}</div>').$init();
@ -39,7 +39,7 @@ describe("ScenarioSpec: Compilation", function(){
scope.$eval();
expect(jqLite(scope.$element).text()).toEqual('3');
});
it("should have $ objects", function(){
scope = compile('<div></div>', {$config: {a:"b"}});
expect(scope.$service('$location')).toBeDefined();
@ -48,7 +48,7 @@ describe("ScenarioSpec: Compilation", function(){
expect(scope.$get('$config.a')).toEqual("b");
});
});
describe("configuration", function(){
it("should take location object", function(){
var url = "http://server/#?book=moby";
@ -61,4 +61,4 @@ describe("ScenarioSpec: Compilation", function(){
expect($location.hashSearch.book).toEqual('moby');
});
});
});
});

View file

@ -52,7 +52,7 @@ describe('scope/model', function(){
model.$eval('name="works"');
expect(model.name).toEqual('works');
});
it('should not bind regexps', function(){
model.exp = /abc/;
expect(model.$eval('exp')).toEqual(model.exp);
@ -158,7 +158,7 @@ describe('scope/model', function(){
var element = jqLite('<div></div>');
var scope = createScope();
scope.$tryEval(function(){throw "myError";}, element);
expect(element.attr('ng-exception')).toEqual('myError');
expect(element.attr('ng-exception')).toEqual('myError');
expect(element.hasClass('ng-exception')).toBeTruthy();
});

View file

@ -1,5 +1,5 @@
describe('ValidatorTest', function(){
it('ShouldHaveThisSet', function() {
var validator = {};
angular.validator.myValidator = function(first, last){
@ -16,7 +16,7 @@ describe('ValidatorTest', function(){
delete angular.validator.myValidator;
scope.$element.remove();
});
it('Regexp', function() {
assertEquals(angular.validator.regexp("abc", /x/, "E1"), "E1");
assertEquals(angular.validator.regexp("abc", '/x/'),
@ -24,7 +24,7 @@ describe('ValidatorTest', function(){
assertEquals(angular.validator.regexp("ab", '^ab$'), null);
assertEquals(angular.validator.regexp("ab", '^axb$', "E3"), "E3");
});
it('Number', function() {
assertEquals(angular.validator.number("ab"), "Not a number");
assertEquals(angular.validator.number("-0.1",0), "Value can not be less than 0.");
@ -32,7 +32,7 @@ describe('ValidatorTest', function(){
assertEquals(angular.validator.number("1.2"), null);
assertEquals(angular.validator.number(" 1 ", 1, 1), null);
});
it('Integer', function() {
assertEquals(angular.validator.integer("ab"), "Not a number");
assertEquals(angular.validator.integer("1.1"), "Not a whole number");
@ -43,7 +43,7 @@ describe('ValidatorTest', function(){
assertEquals(angular.validator.integer("1"), null);
assertEquals(angular.validator.integer(" 1 ", 1, 1), null);
});
it('Date', function() {
var error = "Value is not a date. (Expecting format: 12/31/2009).";
expect(angular.validator.date("ab")).toEqual(error);
@ -60,7 +60,7 @@ describe('ValidatorTest', function(){
expect(angular.validator.date("1/32/2010")).toEqual(error);
expect(angular.validator.date("001/031/2009")).toEqual(error);
});
it('Phone', function() {
var error = "Phone number needs to be in 1(987)654-3210 format in North America or +999 (123) 45678 906 internationaly.";
assertEquals(angular.validator.phone("ab"), error);
@ -68,30 +68,30 @@ describe('ValidatorTest', function(){
assertEquals(null, angular.validator.phone("+421 (0905) 933 297"));
assertEquals(null, angular.validator.phone("+421 0905 933 297"));
});
it('URL', function() {
var error = "URL needs to be in http://server[:port]/path format.";
assertEquals(angular.validator.url("ab"), error);
assertEquals(angular.validator.url("http://server:123/path"), null);
});
it('Email', function() {
var error = "Email needs to be in username@host.com format.";
assertEquals(error, angular.validator.email("ab"));
assertEquals(null, angular.validator.email("misko@hevery.com"));
});
it('Json', function() {
assertNotNull(angular.validator.json("'"));
assertNotNull(angular.validator.json("''X"));
assertNull(angular.validator.json("{}"));
});
describe('asynchronous', function(){
var asynchronous = angular.validator.asynchronous;
var self;
var value, fn;
beforeEach(function(){
value = null;
fn = null;
@ -101,11 +101,11 @@ describe('ValidatorTest', function(){
self.$root = self;
self.$init();
});
afterEach(function(){
if (self.$element) self.$element.remove();
});
it('should make a request and show spinner', function(){
var value, fn;
var scope = compile('<input type="text" name="name" ng:validate="asynchronous:asyncFn"/>');
@ -124,32 +124,32 @@ describe('ValidatorTest', function(){
expect(input.attr(NG_VALIDATION_ERROR)).toEqual("myError");
scope.$element.remove();
});
it("should not make second request to same value", function(){
asynchronous.call(self, "kai", function(v,f){value=v; fn=f;});
expect(value).toEqual('kai');
expect(self.$service('$invalidWidgets')[0]).toEqual(self.$element);
var spy = jasmine.createSpy();
asynchronous.call(self, "kai", spy);
expect(spy).wasNotCalled();
asynchronous.call(self, "misko", spy);
expect(spy).wasCalled();
});
it("should ignore old callbacks, and not remove spinner", function(){
var firstCb, secondCb;
asynchronous.call(self, "first", function(v,f){value=v; firstCb=f;});
asynchronous.call(self, "second", function(v,f){value=v; secondCb=f;});
firstCb();
expect(self.$element.hasClass('ng-input-indicator-wait')).toBeTruthy();
secondCb();
expect(self.$element.hasClass('ng-input-indicator-wait')).toBeFalsy();
});
it("should handle update function", function(){
var scope = angular.compile('<input name="name" ng:validate="asynchronous:asyncFn:updateFn"/>');
scope.asyncFn = jasmine.createSpy();
@ -165,6 +165,6 @@ describe('ValidatorTest', function(){
expect(scope.updateFn.mostRecentCall.args[0]).toEqual({id: 1234, data:'data'});
scope.$element.remove();
});
});
});

View file

@ -1 +1 @@
var _jQuery = jQuery;
var _jQuery = jQuery;

View file

@ -1 +1 @@
var _jQuery = jQuery.noConflict(true);
var _jQuery = jQuery.noConflict(true);

View file

@ -147,6 +147,6 @@ describe("markups", function(){
assertTrue(!hasBindings(parseBindings("a")));
assertTrue(hasBindings(parseBindings("{{b}}x{{c}}")));
});
});

View file

@ -50,11 +50,11 @@ describe('HTML', function(){
});
it('should handle entities', function(){
var everything = '<div rel="!@#$%^&amp;*()_+-={}[]:&#34;;\'&lt;&gt;?,./`~ &#295;">' +
var everything = '<div rel="!@#$%^&amp;*()_+-={}[]:&#34;;\'&lt;&gt;?,./`~ &#295;">' +
'!@#$%^&amp;*()_+-={}[]:&#34;;\'&lt;&gt;?,./`~ &#295;</div>';
expectHTML(everything).toEqual(everything);
});
it('should handle improper html', function(){
expectHTML('< div rel="</div>" alt=abc dir=\'"\' >text< /div>').
toEqual('<div rel="&lt;/div&gt;" alt="abc" dir="&#34;">text</div>');
@ -64,19 +64,19 @@ describe('HTML', function(){
expectHTML('< div rel="</div>" / >').
toEqual('<div rel="&lt;/div&gt;"/>');
});
it('should ignore back slash as escape', function(){
expectHTML('<img alt="xxx\\" title="><script>....">').
toEqual('<img alt="xxx\\" title="&gt;&lt;script&gt;...."/>');
});
it('should ignore object attributes', function(){
expectHTML('<a constructor="hola">:)</a>').
toEqual('<a>:)</a>');
expectHTML('<constructor constructor="hola">:)</constructor>').
toEqual('');
});
describe('htmlSanitizerWriter', function(){
var writer, html;
beforeEach(function(){
@ -118,13 +118,13 @@ describe('HTML', function(){
writer.start('div', {unknown:""});
expect(html).toEqual('<div>');
});
describe('explicitly dissallow', function(){
it('should not allow attributes', function(){
writer.start('div', {id:'a', name:'a', style:'a'});
expect(html).toEqual('<div>');
});
it('should not allow tags', function(){
function tag(name) {
writer.start(name, {});
@ -149,13 +149,13 @@ describe('HTML', function(){
expect(html).toEqual('');
});
});
describe('isUri', function(){
function isUri(value) {
return value.match(URI_REGEXP);
}
it('should be URI', function(){
expect(isUri('http://abc')).toBeTruthy();
expect(isUri('https://abc')).toBeTruthy();
@ -163,7 +163,7 @@ describe('HTML', function(){
expect(isUri('mailto:me@example.com')).toBeTruthy();
expect(isUri('#anchor')).toBeTruthy();
});
it('should not be UIR', function(){
expect(isUri('')).toBeFalsy();
expect(isUri('javascript:alert')).toBeFalsy();

View file

@ -32,7 +32,7 @@ angular.scenario.testing.MockRunner.prototype.on = function(eventName, fn) {
this.listeners[eventName] = this.listeners[eventName] || [];
this.listeners[eventName].push(fn);
};
angular.scenario.testing.MockRunner.prototype.emit = function(eventName) {
var args = Array.prototype.slice.call(arguments, 1);
angular.forEach(this.listeners[eventName] || [], function(fn) {

View file

@ -60,7 +60,7 @@ describe("service", function(){
$log.info();
$log.error();
});
describe('Error', function(){
var e, $log, $console, errorArgs;
beforeEach(function(){
@ -69,12 +69,12 @@ describe("service", function(){
e.sourceURL = undefined;
e.line = undefined;
e.stack = undefined;
$console = angular.service('$log')({console:{error:function(){
errorArgs = arguments;
}}});
});
it('should pass error if does not have trace', function(){
$console.error('abc', e);
expect(errorArgs).toEqual(['abc', e]);
@ -93,9 +93,9 @@ describe("service", function(){
$console.error('abc', e);
expect(errorArgs).toEqual(['abc', 'message\nsourceURL:123']);
});
});
});
describe("$exceptionHandler", function(){