aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/collect.js33
-rw-r--r--docs/filter.template2
-rw-r--r--docs/index.html16
-rw-r--r--docs/overview.template7
-rw-r--r--docs/spec/collectSpec.js47
-rw-r--r--docs/specs.js21
-rw-r--r--docs/widget.template28
-rwxr-xr-xgen_docs.sh2
-rw-r--r--lib/jasmine-1.0.1/index.js180
-rw-r--r--src/Angular.js14
-rw-r--r--src/validators.js4
-rw-r--r--src/widgets.js51
12 files changed, 374 insertions, 31 deletions
diff --git a/docs/collect.js b/docs/collect.js
index f85f2c6b..c16366ab 100644
--- a/docs/collect.js
+++ b/docs/collect.js
@@ -1,8 +1,10 @@
+require.paths.push("./lib");
+require.paths.push(__dirname);
var fs = require('fs'),
spawn = require('child_process').spawn,
- mustache = require('../lib/mustache'),
- callback = require('./callback'),
- markdown = require('../lib/markdown');
+ mustache = require('mustache'),
+ callback = require('callback'),
+ markdown = require('markdown');
var documentation = {
section:{},
@@ -44,7 +46,7 @@ var work = callback.chain(function () {
mergeTemplate('wiki_widgets.js', 'wiki_widgets.js', documentation, callback.chain());
console.log('DONE');
});
-work();
+if (!this.testmode) work();
////////////////////
function noop(){}
@@ -78,6 +80,10 @@ function mergeTemplate(template, output, doc, callback){
}
+function trim(string) {
+ return string.replace(/^[\s\n\r]+/g, '').replace(/[\s\n\r]+$/g, '');
+}
+
function unknownTag(doc, name) {
var error = "[" + doc.raw.file + ":" + doc.raw.line + "]: unknown tag: " + name;
console.log(error);
@@ -93,7 +99,7 @@ function escapedHtmlTag(doc, name, value) {
}
function markdownTag(doc, name, value) {
- doc[name] = markdown.toHTML(value);
+ doc[name] = markdown.toHTML(value.replace(/^#/gm, '##'));
}
var TAG = {
@@ -103,8 +109,10 @@ var TAG = {
namespace: valueTag,
css: valueTag,
see: valueTag,
+ usageContent: valueTag,
'function': valueTag,
description: markdownTag,
+ TODO: markdownTag,
returns: markdownTag,
name: function(doc, name, value) {
doc.name = value;
@@ -113,13 +121,13 @@ var TAG = {
param: function(doc, name, value){
doc.param = doc.param || [];
doc.paramRest = doc.paramRest || [];
- var match = value.match(/^({([^\s=]+)(=)?}\s*)?([^\s]+|\[(\S+)+=([^\]]+)\])\s+(.*)/);
+ var match = value.match(/^({([^\s=]+)(=)?}\s*)?(([^\s=]+)|\[(\S+)+=([^\]]+)\])\s+(.*)/);
if (match) {
var param = {
type: match[2],
- name: match[4] || match[5],
- 'default':match[6],
- description:match[7]};
+ name: match[6] || match[5],
+ 'default':match[7],
+ description:match[8]};
doc.param.push(param);
if (!doc.paramFirst) {
doc.paramFirst = param;
@@ -138,11 +146,11 @@ function parseNgDoc(doc){
var atText;
var match;
doc.raw.text.split(/\n/).forEach(function(line, lineNumber){
- if (match = line.match(/^@(\w+)(\s+(.*))?/)) {
+ if (match = line.match(/^\s*@(\w+)(\s+(.*))?/)) {
// we found @name ...
// if we have existing name
if (atName) {
- (TAG[atName] || unknownTag)(doc, atName, atText.join('\n'));
+ (TAG[atName] || unknownTag)(doc, atName, trim(atText.join('\n')));
}
atName = match[1];
atText = [];
@@ -178,8 +186,9 @@ function findNgDoc(file, callback) {
if (inDoc && line.match(/\*\//)) {
doc.raw.text = doc.raw.text.join('\n');
doc.raw.text = doc.raw.text.replace(/^\n/, '');
- if (doc.raw.text.match(/@ngdoc/))
+ if (doc.raw.text.match(/@ngdoc/)){
callback(doc);
+ }
doc = null;
inDoc = false;
}
diff --git a/docs/filter.template b/docs/filter.template
index f9005782..0602aff9 100644
--- a/docs/filter.template
+++ b/docs/filter.template
@@ -15,7 +15,7 @@ angular.filter.{{shortName}}({{paramFirst.name}}{{#paramRest}}, {{name}}{{/param
<h3>Parameters</h3>
<ul>
{{#param}}
- <li><tt>{{name}}{{#type}}({{type}}){{/type}}</tt>: {{description}}</li>
+ <li><tt>{{name}}:{{#type}}{{type}}{{/type}}{{^type}}:*{{/type}}{{#default}}={{default}}{{/default}}</tt>: {{{description}}}</li>
{{/param}}
</ul>
diff --git a/docs/index.html b/docs/index.html
index f61893a4..a2cad87e 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -6,19 +6,29 @@
<script type="text/javascript" src="../angular.min.js" ng:autobind></script>
<script type="text/javascript" src="http://angularjs.org/extensions/wiki_widgets.js"></script>
<link rel="stylesheet" href="http://angularjs.org/extensions/wiki_widgets.css" type="text/css" media="screen" />
+ <script type="text/javascript">
+ function DocsController() {
+ this.docs = NG_DOC;
+ window.$root = this.$root;
+
+ this.getUrl = function(page){
+ return '#' + encodeURIComponent(page.name);
+ }
+ }
+ </script>
</head>
-<body ng:init="docs=$window.NG_DOC; $window.$root = $root">
+<body ng:controller="DocsController">
<table>
<tr>
<td valign="top">
<div ng:repeat="(name, type) in docs.section">
<b>{{name}}</b>
<div ng:repeat="page in type">
- <a href="#{{page.name}}"><tt>{{page.shortName}}</tt></a>
+ <a href="{{getUrl(page)}}"><tt>{{page.shortName}}</tt></a>
</div>
</div>
</td>
- <td valign="top"><ng:include src="$location.hashPath + '.html' "></ng:include></td>
+ <td valign="top"><ng:include src=" './' + $location.hashPath + '.html' "></ng:include></td>
</tr>
</table>
</body>
diff --git a/docs/overview.template b/docs/overview.template
index dbb91e2a..c4c899e2 100644
--- a/docs/overview.template
+++ b/docs/overview.template
@@ -1 +1,6 @@
-{{{description}}} \ No newline at end of file
+<h1><tt>{{name}}</tt></h1>
+{{{description}}}
+
+<WIKI:SOURCE style="display:block;">
+{{{example}}}
+</WIKI:SOURCE> \ No newline at end of file
diff --git a/docs/spec/collectSpec.js b/docs/spec/collectSpec.js
new file mode 100644
index 00000000..2d1b559c
--- /dev/null
+++ b/docs/spec/collectSpec.js
@@ -0,0 +1,47 @@
+console.log(__dirname);
+require.paths.push(__dirname + "/../");
+require.paths.push(__dirname + "/../../");
+var fs = require('fs');
+var Script = process.binding('evals').Script;
+var collect = load('docs/collect.js');
+
+describe('collect', function(){
+ describe('TAG', function(){
+ var TAG = collect.TAG;
+ describe('@param', function(){
+ var doc;
+ beforeEach(function(){
+ doc = {};
+ });
+ it('should parse with no default', function(){
+ TAG.param(doc, 'param',
+ '{(number|string)} number Number to format.');
+ expect(doc.param).toEqual([{
+ type : '(number|string)',
+ name : 'number',
+ 'default' : undefined,
+ description : 'Number to format.' }]);
+ });
+ it('should parse with default', function(){
+ TAG.param(doc, 'param',
+ '{(number|string)=} [fractionSize=2] desc');
+ expect(doc.param).toEqual([{
+ type : '(number|string)',
+ name : 'fractionSize',
+ 'default' : '2',
+ description : 'desc' }]);
+ });
+ });
+ });
+});
+
+function load(path){
+ var sandbox = {
+ require: require,
+ console: console,
+ __dirname: __dirname,
+ testmode: true
+ };
+ Script.runInNewContext(fs.readFileSync(path), sandbox, path);
+ return sandbox;
+}
diff --git a/docs/specs.js b/docs/specs.js
new file mode 100644
index 00000000..5f1cd153
--- /dev/null
+++ b/docs/specs.js
@@ -0,0 +1,21 @@
+require.paths.push("./lib");
+var jasmine = require('jasmine-1.0.1');
+var sys = require('sys');
+
+for(var key in jasmine) {
+ global[key] = jasmine[key];
+}
+
+var isVerbose = false;
+var showColors = true;
+process.argv.forEach(function(arg){
+ switch(arg) {
+ case '--color': showColors = true; break;
+ case '--noColor': showColors = false; break;
+ case '--verbose': isVerbose = true; break;
+ }
+});
+
+jasmine.executeSpecsInFolder(__dirname + '/spec', function(runner, log){
+ process.exit(runner.results().failedCount);
+}, isVerbose, showColors); \ No newline at end of file
diff --git a/docs/widget.template b/docs/widget.template
new file mode 100644
index 00000000..cf82eac9
--- /dev/null
+++ b/docs/widget.template
@@ -0,0 +1,28 @@
+<h1><tt>{{name}}</tt></h1>
+<h2>Usage</h2>
+<h3>In HTML Template Binding</h3>
+<tt>
+ <pre>
+&lt;{{shortName}}{{#param}} {{#default}}<i>[</i>{{/default}}{{name}}="..."{{#default}}<i>]</i>{{/default}}{{/param}}&gt;{{#usageContent}}
+
+ {{usageContent}}
+{{/usageContent}}&lt;/{{shortName}}&gt;
+ </pre>
+</tt>
+
+<h3>Parameters</h3>
+<ul>
+ {{#param}}
+ <li><tt>{{name}}:{{#type}}{{type}}{{/type}}{{^type}}:*{{/type}}{{#default}}={{default}}{{/default}}</tt>: {{{description}}}</li>
+ {{/param}}
+</ul>
+
+<h3>CSS</h3>
+{{{css}}}
+
+<h2>Description</h2>
+{{{description}}}
+
+<WIKI:SOURCE style="display:block;">
+{{{example}}}
+</WIKI:SOURCE> \ No newline at end of file
diff --git a/gen_docs.sh b/gen_docs.sh
index d883fd34..575287e9 100755
--- a/gen_docs.sh
+++ b/gen_docs.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-/usr/local/bin/node docs/collect.js
+/usr/local/bin/node docs/specs.js --noColor && /usr/local/bin/node docs/collect.js
diff --git a/lib/jasmine-1.0.1/index.js b/lib/jasmine-1.0.1/index.js
new file mode 100644
index 00000000..6c57d20a
--- /dev/null
+++ b/lib/jasmine-1.0.1/index.js
@@ -0,0 +1,180 @@
+var fs = require('fs');
+var sys = require('sys');
+var path = require('path');
+
+var filename = __dirname + '/jasmine.js';
+global.window = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval
+};
+var src = fs.readFileSync(filename);
+var jasmine = process.compile(src + '\njasmine;', filename);
+delete global.window;
+
+function noop(){}
+
+jasmine.executeSpecsInFolder = function(folder, done, isVerbose, showColors, matcher){
+ var log = [];
+ var columnCounter = 0;
+ var start = 0;
+ var elapsed = 0;
+ var verbose = isVerbose || false;
+ var fileMatcher = new RegExp(matcher || "\.js$");
+ var colors = showColors || false;
+ var specs = jasmine.getAllSpecFiles(folder, fileMatcher);
+
+ var ansi = {
+ green: '\033[32m',
+ red: '\033[31m',
+ yellow: '\033[33m',
+ none: '\033[0m'
+ };
+
+ for (var i = 0, len = specs.length; i < len; ++i){
+ var filename = specs[i];
+ require(filename.replace(/\.*$/, ""));
+ }
+
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.reporter = {
+ log: function(str){
+ },
+
+ reportSpecStarting: function(runner) {
+ },
+
+ reportRunnerStarting: function(runner) {
+ sys.puts('Started');
+ start = Number(new Date);
+ },
+
+ reportSuiteResults: function(suite) {
+ var specResults = suite.results();
+ var path = [];
+ while(suite) {
+ path.unshift(suite.description);
+ suite = suite.parentSuite;
+ }
+ var description = path.join(' ');
+
+ if (verbose)
+ log.push('Spec ' + description);
+
+ specResults.items_.forEach(function(spec){
+ if (spec.failedCount > 0 && spec.description) {
+ if (!verbose)
+ log.push(description);
+ log.push(' it ' + spec.description);
+ spec.items_.forEach(function(result){
+ log.push(' ' + result.trace.stack + '\n');
+ });
+ }
+ });
+ },
+
+ reportSpecResults: function(spec) {
+ var result = spec.results();
+ var msg = '';
+ if (result.passed())
+ {
+ msg = (colors) ? (ansi.green + '.' + ansi.none) : '.';
+// } else if (result.skipped) { TODO: Research why "result.skipped" returns false when "xit" is called on a spec?
+// msg = (colors) ? (ansi.yellow + '*' + ansi.none) : '*';
+ } else {
+ msg = (colors) ? (ansi.red + 'F' + ansi.none) : 'F';
+ }
+ sys.print(msg);
+ if (columnCounter++ < 50) return;
+ columnCounter = 0;
+ sys.print('\n');
+ },
+
+
+ reportRunnerResults: function(runner) {
+ elapsed = (Number(new Date) - start) / 1000;
+ sys.puts('\n');
+ log.forEach(function(log){
+ sys.puts(log);
+ });
+ sys.puts('Finished in ' + elapsed + ' seconds');
+
+ var summary = jasmine.printRunnerResults(runner);
+ if(colors)
+ {
+ if(runner.results().failedCount === 0 )
+ sys.puts(ansi.green + summary + ansi.none);
+ else
+ sys.puts(ansi.red + summary + ansi.none);
+ } else {
+ sys.puts(summary);
+ }
+ (done||noop)(runner, log);
+ }
+ };
+ jasmineEnv.execute();
+};
+
+jasmine.getAllSpecFiles = function(dir, matcher){
+ var specs = [];
+
+ if (fs.statSync(dir).isFile() && dir.match(matcher)) {
+ specs.push(dir);
+ } else {
+ var files = fs.readdirSync(dir);
+ for (var i = 0, len = files.length; i < len; ++i){
+ var filename = dir + '/' + files[i];
+ if (fs.statSync(filename).isFile() && filename.match(matcher)){
+ specs.push(filename);
+ }else if (fs.statSync(filename).isDirectory()){
+ var subfiles = this.getAllSpecFiles(filename, matcher);
+ subfiles.forEach(function(result){
+ specs.push(result);
+ });
+ }
+ }
+ }
+
+ return specs;
+};
+
+jasmine.printRunnerResults = function(runner){
+ var results = runner.results();
+ var suites = runner.suites();
+ var msg = '';
+ msg += suites.length + ' test' + ((suites.length === 1) ? '' : 's') + ', ';
+ msg += results.totalCount + ' assertion' + ((results.totalCount === 1) ? '' : 's') + ', ';
+ msg += results.failedCount + ' failure' + ((results.failedCount === 1) ? '' : 's') + '\n';
+ return msg;
+};
+
+function now(){
+ return new Date().getTime();
+}
+
+jasmine.asyncSpecWait = function(){
+ var wait = jasmine.asyncSpecWait;
+ wait.start = now();
+ wait.done = false;
+ (function innerWait(){
+ waits(10);
+ runs(function() {
+ if (wait.start + wait.timeout < now()) {
+ expect('timeout waiting for spec').toBeNull();
+ } else if (wait.done) {
+ wait.done = false;
+ } else {
+ innerWait();
+ }
+ });
+ })();
+};
+jasmine.asyncSpecWait.timeout = 4 * 1000;
+jasmine.asyncSpecDone = function(){
+ jasmine.asyncSpecWait.done = true;
+};
+
+for ( var key in jasmine) {
+ exports[key] = jasmine[key];
+} \ No newline at end of file
diff --git a/src/Angular.js b/src/Angular.js
index 8997045b..0e26a829 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -144,13 +144,6 @@ var _undefined = undefined,
*
*
* @example
- * //TODO this example current doesn't show up anywhere because the overview template doesn't
- * // render it.
- *
- * The following example filter reverses a text string. In addition, it conditionally makes the
- * text upper-case (to demonstrate optional arguments) and assigns color (to demonstrate DOM
- * modification).
-
<script type="text/javascript">
angular.filter.reverse = function(input, uppercase, color) {
var out = "";
@@ -166,12 +159,17 @@ var _undefined = undefined,
return out;
};
</script>
+ The following example filter reverses a text string. In addition, it conditionally makes the
+ text upper-case (to demonstrate optional arguments) and assigns color (to demonstrate DOM
+ modification).
+
+ <hr/>
<span ng:non-bindable="true">{{"hello"|reverse}}</span>: {{"hello"|reverse}}<br>
<span ng:non-bindable="true">{{"hello"|reverse:true}}</span>: {{"hello"|reverse:true}}<br>
<span ng:non-bindable="true">{{"hello"|reverse:true:"blue"}}</span>:
{{"hello"|reverse:true:"blue"}}
- * //TODO: I completely dropped a mention of using the other option (setter method), it's
+ * @TODO: I completely dropped a mention of using the other option (setter method), it's
* confusing to have two ways to do the same thing. I just wonder if we should prefer using the
* setter way over direct assignment because in the future we might want to be able to intercept
* filter registrations for some reason.
diff --git a/src/validators.js b/src/validators.js
index 3eb11f78..fd18d66c 100644
--- a/src/validators.js
+++ b/src/validators.js
@@ -1,4 +1,4 @@
-foreach({
+extend(angularValidator, {
'noop': function() { return _null; },
'regexp': function(value, regexp, msg) {
@@ -132,4 +132,4 @@ foreach({
return inputState.error;
}
-}, function(v,k) {angularValidator[k] = v;});
+});
diff --git a/src/widgets.js b/src/widgets.js
index 5eda5345..7a06fd6c 100644
--- a/src/widgets.js
+++ b/src/widgets.js
@@ -244,13 +244,28 @@ angularWidget('option', function(){
});
-/*ng:doc
- * @type widget
- * @name ng:include
+/**
+ * @ngdoc widget
+ * @name angular.widget.ng:include
*
* @description
+ * Include external HTML fragment.
+ *
+ * Keep in mind that Same Origin Policy applies to included resources
+ * (e.g. ng:include won't work for file:// access).
+ *
+ * @param {string} src expression evaluating to URL.
+ * @param {Scope=} [scope=new_child_scope] expression evaluating to angular.scope
*
* @example
+ * <select name="url">
+ * <option value="angular.filter.date.html">date filter</option>
+ * <option value="angular.filter.html.html">html filter</option>
+ * <option value="">(blank)</option>
+ * </select>
+ * <tt>url = <a href="{{url}}">{{url}}</a></tt>
+ * <hr/>
+ * <ng:include src="url"></ng:include>
*
* @scenario
*/
@@ -299,6 +314,36 @@ angularWidget('ng:include', function(element){
}
});
+/**
+ * @ngdoc widget
+ * @name angular.widget.ng:switch
+ *
+ * @description
+ * Conditionally change the DOM structure.
+ *
+ * @usageContent
+ * <any ng:switch-when="matchValue1"/>...</any>
+ * <any ng:switch-when="matchValue2"/>...</any>
+ * ...
+ * <any ng:switch-when="matchValueN"/>...</any>
+ *
+ * @param {*} on expression to match against <tt>ng:switch-when</tt>.
+ *
+ * @example
+ <select name="switch">
+ <option>settings</option>
+ <option>home</option>
+ </select>
+ <tt>switch={{switch}}</tt>
+ </hr>
+ <ng:switch on="switch" >
+ <div ng:switch-when="settings">Settings Div</div>
+ <span ng:switch-when="home">Home Span</span>
+ </ng:switch>
+ </code>
+ *
+ * @scenario
+ */
var ngSwitch = angularWidget('ng:switch', function (element){
var compiler = this,
watchExpr = element.attr("on"),