diff options
| -rw-r--r-- | docs/collect.js | 33 | ||||
| -rw-r--r-- | docs/filter.template | 2 | ||||
| -rw-r--r-- | docs/index.html | 16 | ||||
| -rw-r--r-- | docs/overview.template | 7 | ||||
| -rw-r--r-- | docs/spec/collectSpec.js | 47 | ||||
| -rw-r--r-- | docs/specs.js | 21 | ||||
| -rw-r--r-- | docs/widget.template | 28 | ||||
| -rwxr-xr-x | gen_docs.sh | 2 | ||||
| -rw-r--r-- | lib/jasmine-1.0.1/index.js | 180 | ||||
| -rw-r--r-- | src/Angular.js | 14 | ||||
| -rw-r--r-- | src/validators.js | 4 | ||||
| -rw-r--r-- | src/widgets.js | 51 | 
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> +<{{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>
\ 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"), | 
