mirror of
https://github.com/zhigang1992/angular.js.git
synced 2026-01-12 22:45:52 +08:00
added documentation for ng:include and ng:widget and test for doc collector.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
{{{description}}}
|
||||
<h1><tt>{{name}}</tt></h1>
|
||||
{{{description}}}
|
||||
|
||||
<WIKI:SOURCE style="display:block;">
|
||||
{{{example}}}
|
||||
</WIKI:SOURCE>
|
||||
47
docs/spec/collectSpec.js
Normal file
47
docs/spec/collectSpec.js
Normal file
@@ -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;
|
||||
}
|
||||
21
docs/specs.js
Normal file
21
docs/specs.js
Normal file
@@ -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);
|
||||
28
docs/widget.template
Normal file
28
docs/widget.template
Normal file
@@ -0,0 +1,28 @@
|
||||
<h1><tt>{{name}}</tt></h1>
|
||||
<h2>Usage</h2>
|
||||
<h3>In HTML Template Binding</h3>
|
||||
<tt>
|
||||
<pre>
|
||||
<{{shortName}}{{#param}} {{#default}}<i>[</i>{{/default}}{{name}}="..."{{#default}}<i>]</i>{{/default}}{{/param}}>{{#usageContent}}
|
||||
|
||||
{{usageContent}}
|
||||
{{/usageContent}}</{{shortName}}>
|
||||
</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>
|
||||
@@ -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
|
||||
|
||||
180
lib/jasmine-1.0.1/index.js
Normal file
180
lib/jasmine-1.0.1/index.js
Normal file
@@ -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];
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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;});
|
||||
});
|
||||
|
||||
@@ -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"),
|
||||
|
||||
Reference in New Issue
Block a user