Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Adding HTML support

  • Loading branch information...
commit dd05e573fb7db5e1afd30911d556c8ec584afa19 1 parent 49d9b95
@bbyars authored
Showing with 6,275 additions and 0 deletions.
  1. +4 −0 server/deps/jade/.gitignore
  2. +21 −0 server/deps/jade/.gitmodules
  3. +4 −0 server/deps/jade/.npmignore
  4. +355 −0 server/deps/jade/History.md
  5. +22 −0 server/deps/jade/LICENSE
  6. +30 −0 server/deps/jade/Makefile
  7. +554 −0 server/deps/jade/Readme.md
  8. +206 −0 server/deps/jade/bin/jade
  9. +2 −0  server/deps/jade/index.js
  10. +2,397 −0 server/deps/jade/jade.js
  11. +2 −0  server/deps/jade/jade.min.js
  12. +401 −0 server/deps/jade/lib/compiler.js
  13. +19 −0 server/deps/jade/lib/doctypes.js
  14. +92 −0 server/deps/jade/lib/filters.js
  15. +316 −0 server/deps/jade/lib/index.js
  16. +316 −0 server/deps/jade/lib/jade.js
  17. +537 −0 server/deps/jade/lib/lexer.js
  18. +31 −0 server/deps/jade/lib/nodes/block-comment.js
  19. +54 −0 server/deps/jade/lib/nodes/block.js
  20. +35 −0 server/deps/jade/lib/nodes/code.js
  21. +32 −0 server/deps/jade/lib/nodes/comment.js
  22. +29 −0 server/deps/jade/lib/nodes/doctype.js
  23. +35 −0 server/deps/jade/lib/nodes/each.js
  24. +35 −0 server/deps/jade/lib/nodes/filter.js
  25. +17 −0 server/deps/jade/lib/nodes/index.js
  26. +14 −0 server/deps/jade/lib/nodes/node.js
  27. +80 −0 server/deps/jade/lib/nodes/tag.js
  28. +42 −0 server/deps/jade/lib/nodes/text.js
  29. +441 −0 server/deps/jade/lib/parser.js
  30. +18 −0 server/deps/jade/lib/self-closing.js
  31. +49 −0 server/deps/jade/lib/utils.js
  32. +19 −0 server/deps/jade/package.json
  33. +58 −0 server/public/stylesheets/application.css
  34. +1 −0  server/views/index.jade
  35. +7 −0 server/views/layout.jade
View
4 server/deps/jade/.gitignore
@@ -0,0 +1,4 @@
+.DS_Store
+lib-cov
+testing
+node_modules
View
21 server/deps/jade/.gitmodules
@@ -0,0 +1,21 @@
+[submodule "support/expresso"]
+ path = support/expresso
+ url = git://github.com/visionmedia/expresso.git
+[submodule "support/sass"]
+ path = support/sass
+ url = git://github.com/visionmedia/sass.js.git
+[submodule "benchmarks/haml-js"]
+ path = benchmarks/haml-js
+ url = git://github.com/creationix/haml-js.git
+[submodule "benchmarks/ejs"]
+ path = benchmarks/ejs
+ url = git://github.com/visionmedia/ejs.git
+[submodule "benchmarks/haml"]
+ path = benchmarks/haml
+ url = git://github.com/visionmedia/haml.js.git
+[submodule "support/coffee-script"]
+ path = support/coffee-script
+ url = http://github.com/jashkenas/coffee-script.git
+[submodule "support/stylus"]
+ path = support/stylus
+ url = git://github.com/LearnBoost/stylus.git
View
4 server/deps/jade/.npmignore
@@ -0,0 +1,4 @@
+test
+support
+benchmarks
+examples
View
355 server/deps/jade/History.md
@@ -0,0 +1,355 @@
+
+0.12.1 / 2011-06-04
+==================
+
+ * Fixed attribute interpolation with double quotes. Fixes #232 [topaxi]
+
+0.12.0 / 2011-06-03
+==================
+
+ * Added `doctype` as alias of `!!!`
+ * Added; doctype value is now case-insensitive
+ * Added attribute interpolation support
+ * Fixed; retain original indentation spaces in text blocks
+
+0.11.1 / 2011-06-01
+==================
+
+ * Fixed text block indentation [Laszlo Bacsi]
+ * Changed; utilizing devDependencies
+ * Fixed try/catch issue with renderFile(). Closes #227
+ * Removed attribute ":" support, use "=" (option for ':' coming soon)
+
+0.11.0 / 2011-05-14
+==================
+
+ * Added `self` object to avoid poor `with(){}` performance [masylum]
+ * Added `doctype` option [Jeremy Larkin]
+
+0.10.7 / 2011-05-04
+==================
+
+ * expose Parser
+
+0.10.6 / 2011-04-29
+==================
+
+ * Fixed CS `Object.keys()` [reported by robholland]
+
+0.10.5 / 2011-04-26
+==================
+
+ * Added error context after the lineno
+ * Added; indicate failing lineno with ">"
+ * Added `Object.keys()` for the client-side
+ * Fixed attr strings when containing the opposite quote. Closes 207
+ * Fixed attr issue with js expressions within strings
+ * Fixed single-quote filter escape bug. Closes #196
+
+
+0.10.4 / 2011-04-05
+==================
+
+ * Added `html` doctype, same as "5"
+ * Fixed `pre`, no longer text-only
+
+0.10.3 / 2011-03-30
+==================
+
+ * Fixed support for quoted attribute keys ex `rss("xmlns:atom"="atom")`
+
+0.10.2 / 2011-03-30
+==================
+
+ * Fixed pipeless text bug with missing outdent
+
+0.10.1 / 2011-03-28
+==================
+
+ * Fixed `support/compile.js` to exclude browser js in node
+ * Fixes for IE [Patrick Pfeiffer]
+
+0.10.0 / 2011-03-25
+==================
+
+ * Added AST-filter support back in the form of `<tag>[attrs]<:><block>`
+
+0.9.3 / 2011-03-24
+==================
+
+ * Added `Block#unshift(node)`
+ * Added `jade.js` for the client-side to the repo
+ * Added `jade.min.js` for the client-side to the repo
+ * Removed need for pipes in filters. Closes #185
+ Note that this _will_ break filters used to
+ manipulate the AST, until we have a different
+ syntax for doing so.
+
+0.9.2 / 2011-03-23
+==================
+
+ * Added jade `--version`
+ * Removed `${}` interpolation support, use `#{}`
+
+0.9.1 / 2011-03-16
+==================
+
+ * Fixed invalid `.map()` call due to recent changes
+
+0.9.0 / 2011-03-16
+==================
+
+ * Added client-side browser support via `make jade.js` and `make jade.min.js`.
+
+0.8.9 / 2011-03-15
+==================
+
+ * Fixed preservation of newlines in text blocks
+
+0.8.8 / 2011-03-14
+==================
+
+ * Fixed jade(1) stdio
+
+0.8.7 / 2011-03-14
+==================
+
+ * Added `mkdirs()` to jade(1)
+ * Added jade(1) stdio support
+ * Added new features to jade(1), `--watch`, recursive compilation etc [khingebjerg]
+ * Fixed pipe-less text newlines
+ * Removed jade(1) `--pipe` flag
+
+0.8.6 / 2011-03-11
+==================
+
+ * Fixed parenthesized expressions in attrs. Closes #170
+ * Changed; default interpolation values `== null` to ''. Closes #167
+
+0.8.5 / 2011-03-09
+==================
+
+ * Added pipe-less text support with immediate ".". Closes #157
+ * Fixed object support in attrs
+ * Fixed array support for attrs
+
+0.8.4 / 2011-03-08
+==================
+
+ * Fixed issue with expressions being evaluated several times. closes #162
+
+0.8.2 / 2011-03-07
+==================
+
+ * Added markdown, discount, and markdown-js support to `:markdown`. Closes #160
+ * Removed `:discount`
+
+0.8.1 / 2011-03-04
+==================
+
+ * Added `pre` pipe-less text support (and auto-escaping)
+
+0.8.0 / 2011-03-04
+==================
+
+ * Added block-expansion support. Closes #74
+ * Added support for multi-line attrs without commas. Closes #65
+
+0.7.1 / 2011-03-04
+==================
+
+ * Fixed `script()` etc pipe-less text with attrs
+
+0.7.0 / 2011-03-04
+==================
+
+ * Removed `:javascript` filter (it doesn't really do anything special, use `script` tags)
+ * Added pipe-less text support. Tags that only accept text nodes (`script`, `textarea`, etc) do not require `|`.
+ * Added `:text` filter for ad-hoc pipe-less
+ * Added flexible indentation. Tabs, arbitrary number of spaces etc
+ * Added conditional-comment support. Closes #146
+ * Added block comment support
+ * Added rss example
+ * Added `:stylus` filter
+ * Added `:discount` filter
+ * Fixed; auto-detect xml and do not self-close tags. Closes #147
+ * Fixed whitespace issue. Closes #118
+ * Fixed attrs. `,`, `=`, and `:` within attr value strings are valid Closes #133
+ * Fixed; only output "" when code == null. Ex: `span.name= user.name` when undefined or null will not output "undefined". Closes #130
+ * Fixed; throw on unexpected token instead of hanging
+
+0.6.3 / 2011-02-02
+==================
+
+ * Added `each` support for Array-like objects [guillermo]
+
+0.6.2 / 2011-02-02
+==================
+
+ * Added CSRF example, showing how you can transparently add inputs to a form
+ * Added link to vim-jade
+ * Fixed self-closing col support [guillermo]
+ * Fixed exception when getAttribute or removeAttribute run into removed attributes [Naitik Shah]
+
+0.6.0 / 2010-12-19
+==================
+
+ * Added unescaped interpolation variant `!{code}`. Closes #124
+ * Changed; escape interpolated code by default `#{code}`
+
+0.5.7 / 2010-12-08
+==================
+
+ * Fixed; hyphen in get `tag()`
+
+0.5.6 / 2010-11-24
+==================
+
+ * Added `exports.compile(str, options)`
+ * Renamed internal `_` to `__`, since `_()` is commonly used for translation
+
+0.5.5 / 2010-10-30
+==================
+
+ * Add _coffeescript_ filter [Michael Hampton]
+ * Added link to _slim_; a ruby implementation
+ * Fixed quoted attributes issue.
+
+ * Fixed attribute issue with over greedy regexp.
+ Previously "p(foo=(((('bar')))))= ((('baz')))"
+ would __fail__ for example since the regexp
+ would lookahead to far. Now we simply pair
+ the delimiters.
+
+0.5.4 / 2010-10-18
+==================
+
+ * Adding newline when using tag code when preceding text
+ * Assume newline in tag text when preceding text
+ * Changed; retain leading text whitespace
+ * Fixed code block support to prevent multiple buffer openings [Jake Luer]
+ * Fixed nested filter support
+
+0.5.3 / 2010-10-06
+==================
+
+ * Fixed bug when tags with code also have a block [reported by chrisirhc]
+
+0.5.2 / 2010-10-05
+==================
+
+ * Added; Text introduces newlines to mimic the grammar.
+ Whitespace handling is a little tricky with this sort of grammar.
+ Jade will now mimic the written grammar, meaning that text blocks
+ using the "|" margin character will introduce a literal newline,
+ where as immediate tag text (ex "a(href='#') Link") will not.
+
+ This may not be ideal, but it makes more sense than what Jade was
+ previously doing.
+
+ * Added `Tag#text` to disambiguate between immediate / block text
+ * Removed _pretty_ option (was kinda useless in the state it was in)
+ * Reverted ignoring of newlines. Closes #92.
+ * Fixed; `Parser#parse()` ignoring newlines
+
+0.5.1 / 2010-10-04
+==================
+
+ * Added many examples
+ * Added; compiler api is now public
+ * Added; filters can accept / manipulate the parse tree
+ * Added filter attribute support. Closes #79
+ * Added LL(*) capabilities
+ * Performance; wrapping code blocks in {} instead of `(function(){}).call(this)`
+ * Performance; Optimized attribute buffering
+ * Fixed trailing newlines in blocks
+
+0.5.0 / 2010-09-11
+==================
+
+ * __Major__ refactor. Logic now separated into lexer/parser/compiler for future extensibility.
+ * Added _pretty_ option
+ * Added parse tree output for _debug_ option
+ * Added new examples
+ * Removed _context_ option, use _scope_
+
+0.4.1 / 2010-09-09
+==================
+
+ * Added support for arbitrary indentation for single-line comments. Closes #71
+ * Only strip first space in text (ex '| foo' will buffer ' foo')
+
+0.4.0 / 2010-08-30
+==================
+
+ * Added tab naive support (tabs are converted to a single indent, aka two spaces). Closes #24
+ * Added unbuffered comment support. Closes #62
+ * Added hyphen support for tag names, ex: "fb:foo-bar"
+ * Fixed bug with single quotes in comments. Closes #61
+ * Fixed comment whitespace issue, previously padding. Closes #55
+
+0.3.0 / 2010-08-04
+==================
+
+ * Added single line comment support. Closes #25
+ * Removed CDATA from _:javascript_ filter. Closes #47
+ * Removed _sys_ local
+ * Fixed code following tag
+
+0.2.4 / 2010-08-02
+==================
+
+ * Added Buffer support to `render()`
+ * Fixed filter text block exception reporting
+ * Fixed tag exception reporting
+
+0.2.3 / 2010-07-27
+==================
+
+ * Fixed newlines before block
+ * Fixed; tag text allowing arbitrary trailing whitespace
+
+0.2.2 / 2010-07-16
+==================
+
+ * Added support for `jade.renderFile()` to utilize primed cache
+ * Added link to [textmate bundle](http://github.com/miksago/jade-tmbundle)
+ * Fixed filter issue with single quotes
+ * Fixed hyphenated attr bug
+ * Fixed interpolation single quotes. Closes #28
+ * Fixed issue with comma in attrs
+
+0.2.1 / 2010-07-09
+==================
+
+ * Added support for node-discount and markdown-js
+ depending on which is available.
+
+ * Added support for tags to have blocks _and_ text.
+ this kinda fucks with arbitrary whitespace unfortunately,
+ but also fixes trailing spaces after tags _with_ blocks.
+
+ * Caching generated functions. Closes #46
+
+0.2.0 / 2010-07-08
+==================
+
+ * Added `- each` support for readable iteration
+ * Added [markdown-js](http://github.com/evilstreak/markdown-js) support (no compilation required)
+ * Removed node-discount support
+
+0.1.0 / 2010-07-05
+==================
+
+ * Added `${}` support for interpolation. Closes #45
+ * Added support for quoted attr keys: `label("for": 'something')` is allowed (_although not required_) [Guillermo]
+ * Added `:less` filter [jakeluer]
+
+0.0.2 / 2010-07-03
+==================
+
+ * Added `context` as synonym for `scope` option [Guillermo]
+ * Fixed attr splitting: `div(style:"color: red")` is now allowed
+ * Fixed issue with `(` and `)` within attrs: `a(class: (a ? 'a' : 'b'))` is now allowed
+ * Fixed issue with leading / trailing spaces in attrs: `a( href="#" )` is now allowed [Guillermo]
+
View
22 server/deps/jade/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2009-2010 TJ Holowaychuk <tj@vision-media.ca>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
30 server/deps/jade/Makefile
@@ -0,0 +1,30 @@
+
+TESTS = test/*.js
+SRC = $(shell find lib -name "*.js" -type f)
+UGLIFY_FLAGS = --no-mangle
+
+test:
+ @./node_modules/.bin/expresso \
+ -I lib \
+ $(TESTS)
+
+benchmark:
+ @node benchmarks/jade.js \
+ && node benchmarks/jade-self.js \
+ && node benchmarks/haml.js \
+ && node benchmarks/haml2.js \
+ && node benchmarks/ejs.js
+
+jade.js: $(SRC)
+ @node support/compile.js $^
+
+jade.min.js: jade.js
+ @uglifyjs $(UGLIFY_FLAGS) $< > $@ \
+ && du jade.min.js \
+ && du jade.js
+
+clean:
+ rm -f jade.js
+ rm -f jade.min.js
+
+.PHONY: test benchmark clean
View
554 server/deps/jade/Readme.md
@@ -0,0 +1,554 @@
+
+# Jade - template engine
+
+ Jade is a high performance template engine heavily influenced by [Haml](http://haml-lang.com)
+ and implemented with JavaScript for [node](http://nodejs.org).
+
+## Features
+
+ - client-side support
+ - great readability
+ - flexible indentation
+ - block-expansion
+ - attribute interpolation
+ - code is escaped by default for security
+ - contextual error reporting at compile &amp; run time
+ - executable for compiling jade templates via the command line
+ - html 5 mode (using the _!!! 5_ doctype)
+ - optional memory caching
+ - combine dynamic and static tag classes
+ - parse tree manipulation via _filters_
+ - supports [Express JS](http://expressjs.com) out of the box
+ - transparent iteration over objects, arrays, and even non-enumerables via `- each`
+ - block comments
+ - no tag prefix
+ - AST filters
+ - filters
+ - :sass must have [sass.js](http://github.com/visionmedia/sass.js) installed
+ - :less must have [less.js](http://github.com/cloudhead/less.js) installed
+ - :markdown must have [markdown-js](http://github.com/evilstreak/markdown-js) installed or [node-discount](http://github.com/visionmedia/node-discount)
+ - :cdata
+ - :coffeescript must have [coffee-script](http://jashkenas.github.com/coffee-script/) installed
+ - [Vim Syntax](https://github.com/digitaltoad/vim-jade)
+ - [TextMate Bundle](http://github.com/miksago/jade-tmbundle)
+ - [Screencasts](http://tjholowaychuk.com/post/1004255394/jade-screencast-template-engine-for-nodejs)
+ - [html2jade](https://github.com/donpark/html2jade) converter
+
+## Implementations
+
+ - [php](http://github.com/everzet/jade.php)
+ - [scala](http://scalate.fusesource.org/versions/snapshot/documentation/scaml-reference.html)
+ - [ruby](http://github.com/stonean/slim)
+
+## Installation
+
+via npm:
+
+ npm install jade
+
+## Browser Support
+
+ To compile jade to a single file compatible for client-side use simply execute:
+
+ $ make jade.js
+
+ Alternatively, if uglifyjs is installed via npm (`npm install uglify-js`) you may execute the following which will create both files.
+
+ $ make jade.min.js
+
+## Public API
+
+```javascript
+ var jade = require('jade');
+
+ // Render a string
+ jade.render('string of jade', { options: 'here' });
+
+ // Render a file
+ jade.renderFile('path/to/some.jade', { options: 'here' }, function(err, html){
+ // options are optional,
+ // the callback can be the second arg
+ });
+
+ // Compile a function
+ var fn = jade.compile('string of jade', options);
+ fn.call(scope, locals);
+```
+
+### Options
+
+ - `scope` Evaluation scope (`this`)
+ - `self` Use a `self` namespace to hold the locals. _false by default_
+ - `locals` Local variable object
+ - `filename` Used in exceptions, and required by `cache`
+ - `cache` Cache intermediate JavaScript in memory keyed by `filename`
+ - `debug` Outputs tokens and function body generated
+ - `compiler` Compiler to replace jade's default
+
+## Syntax
+
+### Line Endings
+
+**CRLF** and **CR** are converted to **LF** before parsing.
+
+### Tags
+
+A tag is simply a leading word:
+
+ html
+
+for example is converted to `<html></html>`
+
+tags can also have ids:
+
+ div#container
+
+which would render `<div id="container"></div>`
+
+how about some classes?
+
+ div.user-details
+
+renders `<div class="user-details"></div>`
+
+multiple classes? _and_ an id? sure:
+
+ div#foo.bar.baz
+
+renders `<div id="foo" class="bar baz"></div>`
+
+div div div sure is annoying, how about:
+
+ #foo
+ .bar
+
+which is syntactic sugar for what we have already been doing, and outputs:
+
+ `<div id="foo"></div><div class="bar"></div>`
+
+### Tag Text
+
+Simply place some content after the tag:
+
+ p wahoo!
+
+renders `<p>wahoo!</p>`.
+
+well cool, but how about large bodies of text:
+
+ p
+ | foo bar baz
+ | rawr rawr
+ | super cool
+ | go jade go
+
+renders `<p>foo bar baz rawr.....</p>`
+
+interpolation? yup! both types of text can utilize interpolation,
+if we passed `{ locals: { name: 'tj', email: 'tj@vision-media.ca' }}` to `render()`
+we can do the following:
+
+ #user #{name} &lt;#{email}&gt;
+
+outputs `<div id="user">tj &lt;tj@vision-media.ca&gt;</div>`
+
+Actually want `#{}` for some reason? escape it!
+
+ p \#{something}
+
+now we have `<p>#{something}</p>`
+
+We can also utilize the unescaped variant `!{html}`, so the following
+will result in a literal script tag:
+
+ - var html = "<script></script>"
+ | !{html}
+
+Nested tags that also contain text can optionally use a text block:
+
+ label
+ | Username:
+ input(name='user[name]')
+
+or immediate tag text:
+
+ label Username:
+ input(name='user[name]')
+
+Tags that accept _only_ text such as `script`, `style`, and `textarea` do not
+need the leading `|` character, for example:
+
+ html
+ head
+ title Example
+ script
+ if (foo) {
+ bar();
+ } else {
+ baz();
+ }
+
+Once again as an alternative, we may use a leading '.' to indicate a text block, for example:
+
+ p.
+ foo asdf
+ asdf
+ asdfasdfaf
+ asdf
+ asd.
+
+outputs:
+
+ <p>foo asdf
+ asdf
+ asdfasdfaf
+ asdf
+ asd
+ .
+ </p>
+
+This however differs from a leading '.' followed by a space, which although is ignored by the Jade parser, tells Jade that this period is a literal:
+
+ p .
+
+outputs:
+
+ <p>.</p>
+
+### Comments
+
+Single line comments currently look the same as JavaScript comments,
+aka "//" and must be placed on their own line:
+
+ // just some paragraphs
+ p foo
+ p bar
+
+would output
+
+ <!-- just some paragraphs -->
+ <p>foo</p>
+ <p>bar</p>
+
+Jade also supports unbuffered comments, by simply adding a hyphen:
+
+ //- will not output within markup
+ p foo
+ p bar
+
+outputting
+
+ <p>foo</p>
+ <p>bar</p>
+
+### Block Comments
+
+ A block comment is legal as well:
+
+ body
+ //
+ #content
+ h1 Example
+
+outputting
+
+ <body>
+ <!--
+ <div id="content">
+ <h1>Example</h1>
+ </div>
+ -->
+ </body>
+
+Jade supports conditional-comments as well, for example:
+
+ body
+ /if IE
+ a(href='http://www.mozilla.com/en-US/firefox/') Get Firefox
+
+outputs:
+
+ <body>
+ <!--[if IE]>
+ <a href="http://www.mozilla.com/en-US/firefox/">Get Firefox</a>
+ <![endif]-->
+ </body>
+
+
+### Nesting
+
+ Jade supports nesting to define the tags in a natural way:
+
+ ul
+ li.first
+ a(href='#') foo
+ li
+ a(href='#') bar
+ li.last
+ a(href='#') baz
+
+### Block Expansion
+
+ Block expansion allows you to create terse single-line nested tags,
+ the following example is equivalent to the nesting example above.
+
+ ul
+ li.first: a(href='#') foo
+ li: a(href='#') bar
+ li.last: a(href='#') baz
+
+
+### Attributes
+
+Jade currently supports '(' and ')' as attribute delimiters.
+
+ a(href='/login', title='View login page') Login
+
+Boolean attributes are also supported:
+
+ input(type="checkbox", checked)
+
+Boolean attributes with code will only output the attribute when `true`:
+
+ input(type="checkbox", checked= someValue)
+
+Multiple lines work too:
+
+ input(type='checkbox',
+ name='agreement',
+ checked)
+
+Multiple lines without the comma work fine:
+
+ input(type='checkbox'
+ name='agreement'
+ checked)
+
+Funky whitespace? fine:
+
+
+ input(
+ type='checkbox'
+ name='agreement'
+ checked)
+
+Colons work:
+
+ rss(xmlns:atom="atom")
+
+Suppose we have the `user` local `{ id: 12, name: 'tobi' }`
+and we wish to create an anchor tag with `href` pointing to "/user/12"
+we could use regular javascript concatenation:
+
+ a(href='/user/' + user.id)= user.name
+
+or we could use jade's interpolation:
+
+ a(href='/user/#{user.id}')= user.name
+
+### Doctypes
+
+To add a doctype simply use `!!!`, or `doctype` followed by an optional value:
+
+ !!!
+
+Will output the _transitional_ doctype, however:
+
+ !!! 5
+
+or
+
+ !!! html
+
+or
+
+ doctype html
+
+doctypes are case-insensitive, so the following are equivalent:
+
+ doctype Basic
+ doctype basic
+
+Will output the _html 5_ doctype. Below are the doctypes
+defined by default, which can easily be extended:
+
+```javascript
+ var doctypes = exports.doctypes = {
+ '5': '<!DOCTYPE html>',
+ 'xml': '<?xml version="1.0" encoding="utf-8" ?>',
+ 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
+ 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
+ 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">',
+ 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">',
+ '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">',
+ 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">',
+ 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
+ };
+```
+
+To alter the default simply change:
+
+```javascript
+ jade.doctypes.default = 'whatever you want';
+```
+
+## Filters
+
+Filters are prefixed with `:`, for example `:markdown` and
+pass the following block of text to an arbitrary function for processing. View the _features_
+at the top of this document for available filters.
+
+ body
+ :markdown
+ Woah! jade _and_ markdown, very **cool**
+ we can even link to [stuff](http://google.com)
+
+Renders:
+
+ <body><p>Woah! jade <em>and</em> markdown, very <strong>cool</strong> we can even link to <a href="http://google.com">stuff</a></p></body>
+
+Filters may also manipulate the parse tree. For example perhaps I want to
+bake conditionals right into jade, we could do so with a filter named _conditionals_. Typically filters work on text blocks, however by passing a regular block our filter can do anything it wants with the tags nested within it.
+
+ body
+ conditionals:
+ if role == 'admin'
+ p You are amazing
+ else
+ p Not so amazing
+
+Not that we no longer prefix with "-" for these code blocks. Examples of
+how to manipulate the parse tree can be found at _./examples/conditionals.js_ and _./examples/model.js_, basically we subclass and re-implement visitor methods as needed. There are several interesting use-cases for this functionality above what was shown above such as transparently aggregating / compressing assets to reduce the number of HTTP requests, transparent record error reporting, and more.
+
+## Code
+
+Jade currently supports three classifications of executable code. The first
+is prefixed by `-`, and is not buffered:
+
+ - var foo = 'bar';
+
+This can be used for conditionals, or iteration:
+
+ - for (var key in obj)
+ p= obj[key]
+
+Due to Jade's buffering techniques the following is valid as well:
+
+ - if (foo)
+ ul
+ li yay
+ li foo
+ li worked
+ - else
+ p oh no! didnt work
+
+Hell, even verbose iteration:
+
+ - if (items.length)
+ ul
+ - items.forEach(function(item){
+ li= item
+ - })
+
+Anything you want!
+
+Next up we have _escaped_ buffered code, which is used to
+buffer a return value, which is prefixed by `=`:
+
+ - var foo = 'bar'
+ = foo
+ h1= foo
+
+Which outputs `bar<h1>bar</h1>`. Code buffered by `=` is escaped
+by default for security, however to output unescaped return values
+you may use `!=`:
+
+ p!= aVarContainingMoreHTML
+
+The on exception made in terms of allowing "vanilla" JavaScript, is
+the `- each` token. This takes the form of:
+
+ - each VAL[, KEY] in OBJ
+
+An example iterating over an array:
+
+ - var items = ["one", "two", "three"]
+ - each item in items
+ li= item
+
+outputs:
+
+ <li>one</li>
+ <li>two</li>
+ <li>three</li>
+
+iterating an object's keys and values:
+
+ - var obj = { foo: 'bar' }
+ - each val, key in obj
+ li #{key}: #{val}
+
+would output `<li>foo: bar</li>`
+
+You can also nest these!
+
+ - each user in users
+ - each role in user.roles
+ li= role
+
+When a property is undefined, Jade will output an empty string. For example:
+
+ textarea= user.signature
+
+when undefined would normally output "undefined" in your html, however recent
+versions of Jade will simply render:
+
+ <textarea></textarea>
+
+## bin/jade
+
+Output html to _stdout_:
+
+ jade examples/*.jade --pipe
+
+Generate _examples/*.html_:
+
+ jade examples/*.jade
+
+Pass options:
+
+ jade examples/layout.jade --options '{ locals: { title: "foo" }}'
+
+Usage info:
+
+ Usage: jade [options] <path ...>
+
+ Options:
+ -o, --options STR JavaScript options object passed
+ -p, --pipe Output to stdout instead of PATH.html
+ -h, --help Output help information
+
+## License
+
+(The MIT License)
+
+Copyright (c) 2009-2010 TJ Holowaychuk &lt;tj@vision-media.ca&gt;
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
View
206 server/deps/jade/bin/jade
@@ -0,0 +1,206 @@
+#!/usr/bin/env node
+
+/**
+ * Module dependencies.
+ */
+
+var fs = require('fs')
+ , path = require('path')
+ , resolve = path.resolve
+ , basename = path.basename
+ , dirname = path.dirname
+ , jade;
+
+try {
+ jade = require('../lib/jade');
+} catch (err) {
+ jade = require('jade');
+}
+
+/**
+ * Arguments.
+ */
+
+var args = process.argv.slice(2);
+
+/**
+ * Options javascript.
+ */
+
+var options = {};
+
+/**
+ * Destination dir.
+ */
+
+var dest;
+
+/**
+ * Watcher hash.
+ */
+
+var watchers;
+
+/**
+ * Usage information.
+ */
+
+var usage = ''
+ + '\n'
+ + ' Usage: jade [options]\n'
+ + ' [path ...]\n'
+ + ' < in.jade > out.jade'
+ + ' \n'
+ + ' Options:\n'
+ + ' -o, --options <str> JavaScript options object passed\n'
+ + ' -h, --help Output help information\n'
+ + ' -w, --watch Watch file(s) or folder(s) for changes and re-compile\n'
+ + ' -v, --version Output jade version\n'
+ + ' --out <dir> Output the compiled html to <dir>\n';
+ + '\n';
+
+// Parse arguments
+
+var arg
+ , files = [];
+while (args.length) {
+ arg = args.shift();
+ switch (arg) {
+ case '-h':
+ case '--help':
+ console.log(usage);
+ process.exit(1);
+ case '-v':
+ case '--version':
+ console.log(jade.version);
+ process.exit(1);
+ case '-o':
+ case '--options':
+ var str = args.shift();
+ if (str) {
+ options = eval('(' + str + ')');
+ } else {
+ console.error('-o, --options requires a string.');
+ process.exit(1);
+ }
+ break;
+ case '-w':
+ case '--watch':
+ watchers = {};
+ break;
+ case '--out':
+ dest = args.shift();
+ break;
+ default:
+ files.push(arg);
+ }
+}
+
+// Watching and no files passed - watch cwd
+if (watchers && !files.length) {
+ fs.readdirSync(process.cwd()).forEach(processFile);
+// Process passed files
+} else if (files.length) {
+ files.forEach(processFile);
+// Stdio
+} else {
+ var buf = '';
+ process.stdin.setEncoding('utf8');
+ process.stdin.on('data', function(chunk){
+ buf += chunk;
+ }).on('end', function(){
+ console.log(jade.render(buf, options));
+ }).resume();
+}
+
+/**
+ * Process the given path, compiling the jade files found.
+ * Always walk the subdirectories.;
+ */
+
+function processFile(path) {
+ fs.lstat(path, function(err, stat) {
+ if (err) throw err;
+ // Found jade file
+ if (stat.isFile() && path.match(/\.jade$/)) {
+ renderJade(path);
+ // Found directory
+ } else if (stat.isDirectory()) {
+ fs.readdir(path, function(err, files) {
+ if (err) throw err;
+ files.map(function(filename) {
+ return path + '/' + filename;
+ }).forEach(processFile);
+ });
+ }
+ });
+}
+
+/**
+ * Render jade
+ */
+
+function renderJade(jadefile) {
+ jade.renderFile(jadefile, options, function(err, html) {
+ if (err) throw err;
+ writeFile(jadefile, html);
+ });
+}
+
+/**
+ * mkdir -p implementation.
+ */
+
+function mkdirs(path, fn) {
+ var segs = dirname(path).split('/')
+ , dir = '';
+
+ (function next() {
+ var seg = segs.shift();
+ if (seg) {
+ dir += seg + '/';
+ fs.mkdir(dir, 0755, function(err){
+ if (!err) return next();
+ if ('EEXIST' == err.code) return next();
+ });
+ } else {
+ fn();
+ }
+ })();
+}
+
+/**
+ * Write the html output to a file.
+ */
+
+function writeFile(src, html) {
+ var path = src.replace('.jade', '.html');
+ if (dest) path = dest + '/' + path;
+ mkdirs(path, function(err){
+ if (err) throw err;
+ fs.writeFile(path, html, function(err) {
+ if (err) throw err;
+ console.log(' \033[90mcompiled\033[0m %s', path);
+ watch(src, renderJade);
+ });
+ });
+}
+
+/**
+ * Watch the given `file` and invoke `fn` when modified.
+ */
+
+function watch(file, fn) {
+ // not watching
+ if (!watchers) return;
+
+ // already watched
+ if (watchers[file]) return;
+
+ // watch the file itself
+ watchers[file] = true;
+ console.log(' \033[90mwatching\033[0m %s', file);
+ fs.watchFile(file, { interval: 50 }, function(curr, prev){
+ if (curr.mtime > prev.mtime) fn(file);
+ });
+}
View
2  server/deps/jade/index.js
@@ -0,0 +1,2 @@
+
+module.exports = require('./lib/jade');
View
2,397 server/deps/jade/jade.js
@@ -0,0 +1,2397 @@
+
+// CommonJS require()
+
+function require(p){
+ var path = require.resolve(p)
+ , mod = require.modules[path];
+ if (!mod) throw new Error('failed to require "' + p + '"');
+ if (!mod.exports) {
+ mod.exports = {};
+ mod.call(mod.exports, mod, mod.exports, require.relative(path));
+ }
+ return mod.exports;
+ }
+
+require.modules = {};
+
+require.resolve = function (path){
+ var orig = path
+ , reg = path + '.js'
+ , index = path + '/index.js';
+ return require.modules[reg] && reg
+ || require.modules[index] && index
+ || orig;
+ };
+
+require.register = function (path, fn){
+ require.modules[path] = fn;
+ };
+
+require.relative = function (parent) {
+ return function(p){
+ if ('.' != p[0]) return require(p);
+
+ var path = parent.split('/')
+ , segs = p.split('/');
+ path.pop();
+
+ for (var i = 0; i < segs.length; i++) {
+ var seg = segs[i];
+ if ('..' == seg) path.pop();
+ else if ('.' != seg) path.push(seg);
+ }
+
+ return require(path.join('/'));
+ };
+ };
+
+
+require.register("compiler.js", function(module, exports, require){
+
+/*!
+ * Jade - Compiler
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var nodes = require('./nodes')
+ , filters = require('./filters')
+ , doctypes = require('./doctypes')
+ , selfClosing = require('./self-closing')
+ , utils = require('./utils');
+
+
+ if (!Object.keys) {
+ Object.keys = function(obj){
+ var arr = [];
+ for (var key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ arr.push(obj);
+ }
+ }
+ return arr;
+ }
+ }
+
+ if (!String.prototype.trimLeft) {
+ String.prototype.trimLeft = function(){
+ return this.replace(/^\s+/, '');
+ }
+ }
+
+
+
+/**
+ * Initialize `Compiler` with the given `node`.
+ *
+ * @param {Node} node
+ * @param {Object} options
+ * @api public
+ */
+
+var Compiler = module.exports = function Compiler(node, options) {
+ this.options = options = options || {};
+ this.node = node;
+ this.hasCompiledDoctype = false;
+ this.hasCompiledTag = false;
+ if (options.doctype) this.setDoctype(options.doctype);
+};
+
+/**
+ * Compiler prototype.
+ */
+
+Compiler.prototype = {
+
+ /**
+ * Compile parse tree to JavaScript.
+ *
+ * @api public
+ */
+
+ compile: function(){
+ this.buf = ['var interp;'];
+ this.visit(this.node);
+ return this.buf.join('\n');
+ },
+
+ /**
+ * Sets the default doctype `name`. Sets terse mode to `true` when
+ * html 5 is used, causing self-closing tags to end with ">" vs "/>",
+ * and boolean attributes are not mirrored.
+ *
+ * @param {string} name
+ * @api public
+ */
+
+ setDoctype: function(name){
+ var doctype = doctypes[(name || 'default').toLowerCase()];
+ if (!doctype) throw new Error('unknown doctype "' + name + '"');
+ this.doctype = doctype;
+ this.terse = '5' == name || 'html' == name;
+ this.xml = 0 == this.doctype.indexOf('<?xml');
+ },
+
+ /**
+ * Buffer the given `str` optionally escaped.
+ *
+ * @param {String} str
+ * @param {Boolean} esc
+ * @api public
+ */
+
+ buffer: function(str, esc){
+ if (esc) str = utils.escape(str);
+ this.buf.push("buf.push('" + str + "');");
+ },
+
+ /**
+ * Buffer the given `node`'s lineno.
+ *
+ * @param {Node} node
+ * @api public
+ */
+
+ line: function(node){
+ if (node.instrumentLineNumber === false) return;
+ this.buf.push('__.lineno = ' + node.line + ';');
+ },
+
+ /**
+ * Visit `node`.
+ *
+ * @param {Node} node
+ * @api public
+ */
+
+ visit: function(node){
+ this.line(node);
+ return this.visitNode(node);
+ },
+
+ /**
+ * Visit `node`.
+ *
+ * @param {Node} node
+ * @api public
+ */
+
+ visitNode: function(node){
+ var name = node.constructor.name
+ || node.constructor.toString().match(/function ([^(\s]+)()/)[1];
+ return this['visit' + name](node);
+ },
+
+ /**
+ * Visit all nodes in `block`.
+ *
+ * @param {Block} block
+ * @api public
+ */
+
+ visitBlock: function(block){
+ var len = len = block.nodes.length;
+ for (var i = 0; i < len; ++i) {
+ this.visit(block.nodes[i]);
+ }
+ },
+
+ /**
+ * Visit `doctype`. Sets terse mode to `true` when html 5
+ * is used, causing self-closing tags to end with ">" vs "/>",
+ * and boolean attributes are not mirrored.
+ *
+ * @param {Doctype} doctype
+ * @api public
+ */
+
+ visitDoctype: function(doctype){
+ if (doctype && (doctype.val || !this.doctype)) {
+ this.setDoctype(doctype.val || 'default');
+ }
+
+ if (this.doctype) this.buffer(this.doctype);
+ this.hasCompiledDoctype = true;
+ },
+
+ /**
+ * Visit `tag` buffering tag markup, generating
+ * attributes, visiting the `tag`'s code and block.
+ *
+ * @param {Tag} tag
+ * @api public
+ */
+
+ visitTag: function(tag){
+ var name = tag.name;
+
+ if (!this.hasCompiledTag) {
+ if (!this.hasCompiledDoctype && 'html' == name) {
+ this.visitDoctype();
+ }
+ this.hasCompiledTag = true;
+ }
+
+ if (~selfClosing.indexOf(name) && !this.xml) {
+ this.buffer('<' + name);
+ this.visitAttributes(tag.attrs);
+ this.terse
+ ? this.buffer('>')
+ : this.buffer('/>');
+ } else {
+ // Optimize attributes buffering
+ if (tag.attrs.length) {
+ this.buffer('<' + name);
+ if (tag.attrs.length) this.visitAttributes(tag.attrs);
+ this.buffer('>');
+ } else {
+ this.buffer('<' + name + '>');
+ }
+ if (tag.code) this.visitCode(tag.code);
+ if (tag.text) this.buffer(utils.text(tag.text.nodes[0].trimLeft()));
+ this.escape = 'pre' == tag.name;
+ this.visit(tag.block);
+ this.buffer('</' + name + '>');
+ }
+ },
+
+ /**
+ * Visit `filter`, throwing when the filter does not exist.
+ *
+ * @param {Filter} filter
+ * @api public
+ */
+
+ visitFilter: function(filter){
+ var fn = filters[filter.name];
+
+ // unknown filter
+ if (!fn) {
+ if (filter.isASTFilter) {
+ throw new Error('unknown ast filter "' + filter.name + ':"');
+ } else {
+ throw new Error('unknown filter ":' + filter.name + '"');
+ }
+ }
+ if (filter.isASTFilter) {
+ this.buf.push(fn(filter.block, this, filter.attrs));
+ } else {
+ var text = filter.block.nodes.join('');
+ this.buffer(utils.text(fn(text, filter.attrs)));
+ }
+ },
+
+ /**
+ * Visit `text` node.
+ *
+ * @param {Text} text
+ * @api public
+ */
+
+ visitText: function(text){
+ text = utils.text(text.nodes.join(''));
+ if (this.escape) text = escape(text);
+ this.buffer(text);
+ this.buffer('\\n');
+ },
+
+ /**
+ * Visit a `comment`, only buffering when the buffer flag is set.
+ *
+ * @param {Comment} comment
+ * @api public
+ */
+
+ visitComment: function(comment){
+ if (!comment.buffer) return;
+ this.buffer('<!--' + utils.escape(comment.val) + '-->');
+ },
+
+ /**
+ * Visit a `BlockComment`.
+ *
+ * @param {Comment} comment
+ * @api public
+ */
+
+ visitBlockComment: function(comment){
+ if (0 == comment.val.indexOf('if')) {
+ this.buffer('<!--[' + comment.val + ']>');
+ this.visit(comment.block);
+ this.buffer('<![endif]-->');
+ } else {
+ this.buffer('<!--' + comment.val);
+ this.visit(comment.block);
+ this.buffer('-->');
+ }
+ },
+
+ /**
+ * Visit `code`, respecting buffer / escape flags.
+ * If the code is followed by a block, wrap it in
+ * a self-calling function.
+ *
+ * @param {Code} code
+ * @api public
+ */
+
+ visitCode: function(code){
+ // Wrap code blocks with {}.
+ // we only wrap unbuffered code blocks ATM
+ // since they are usually flow control
+
+ // Buffer code
+ if (code.buffer) {
+ var val = code.val.trimLeft();
+ this.buf.push('var __val__ = ' + val);
+ val = 'null == __val__ ? "" : __val__';
+ if (code.escape) val = 'escape(' + val + ')';
+ this.buf.push("buf.push(" + val + ");");
+ } else {
+ this.buf.push(code.val);
+ }
+
+ // Block support
+ if (code.block) {
+ if (!code.buffer) this.buf.push('{');
+ this.visit(code.block);
+ if (!code.buffer) this.buf.push('}');
+ }
+ },
+
+ /**
+ * Visit `each` block.
+ *
+ * @param {Each} each
+ * @api public
+ */
+
+ visitEach: function(each){
+ this.buf.push(''
+ + '// iterate ' + each.obj + '\n'
+ + '(function(){\n'
+ + ' if (\'number\' == typeof ' + each.obj + '.length) {\n'
+ + ' for (var ' + each.key + ' = 0, $$l = ' + each.obj + '.length; ' + each.key + ' < $$l; ' + each.key + '++) {\n'
+ + ' var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
+
+ this.visit(each.block);
+
+ this.buf.push(''
+ + ' }\n'
+ + ' } else {\n'
+ + ' for (var ' + each.key + ' in ' + each.obj + ') {\n'
+ + ' if (' + each.obj + '.hasOwnProperty(' + each.key + ')){'
+ + ' var ' + each.val + ' = ' + each.obj + '[' + each.key + '];\n');
+
+ this.visit(each.block);
+
+ this.buf.push(' }\n');
+
+ this.buf.push(' }\n }\n}).call(this);\n');
+ },
+
+ /**
+ * Visit `attrs`.
+ *
+ * @param {Array} attrs
+ * @api public
+ */
+
+ visitAttributes: function(attrs){
+ var buf = []
+ , classes = [];
+
+ if (this.terse) buf.push('terse: true');
+
+ attrs.forEach(function(attr){
+ if (attr.name == 'class') {
+ classes.push('(' + attr.val + ')');
+ } else {
+ var pair = "'" + attr.name + "':(" + attr.val + ')';
+ buf.push(pair);
+ }
+ });
+
+ if (classes.length) {
+ classes = classes.join(" + ' ' + ");
+ buf.push("class: " + classes);
+ }
+
+ buf = buf.join(', ').replace('class:', '"class":');
+
+ this.buf.push("buf.push(attrs({ " + buf + " }));");
+ }
+};
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+function escape(html){
+ return String(html)
+ .replace(/&(?!\w+;)/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;');
+}
+
+}); // module: compiler.js
+
+require.register("doctypes.js", function(module, exports, require){
+
+/*!
+ * Jade - doctypes
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+module.exports = {
+ '5': '<!DOCTYPE html>'
+ , 'html': '<!DOCTYPE html>'
+ , 'xml': '<?xml version="1.0" encoding="utf-8" ?>'
+ , 'default': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
+ , 'transitional': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
+ , 'strict': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
+ , 'frameset': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">'
+ , '1.1': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">'
+ , 'basic': '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">'
+ , 'mobile': '<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">'
+};
+}); // module: doctypes.js
+
+require.register("filters.js", function(module, exports, require){
+
+/*!
+ * Jade - filters
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+module.exports = {
+
+ /**
+ * Wrap text with CDATA block.
+ */
+
+ cdata: function(str){
+ return '<![CDATA[\\n' + str + '\\n]]>';
+ },
+
+ /**
+ * Transform sass to css, wrapped in style tags.
+ */
+
+ sass: function(str){
+ str = str.replace(/\\n/g, '\n');
+ var sass = require('sass').render(str).replace(/\n/g, '\\n');
+ return '<style>' + sass + '</style>';
+ },
+
+ /**
+ * Transform stylus to css, wrapped in style tags.
+ */
+
+ stylus: function(str, options){
+ var ret;
+ str = str.replace(/\\n/g, '\n');
+ var stylus = require('stylus');
+ stylus(str, options).render(function(err, css){
+ if (err) throw err;
+ ret = css.replace(/\n/g, '\\n');
+ });
+ return '<style>' + ret + '</style>';
+ },
+
+ /**
+ * Transform sass to css, wrapped in style tags.
+ */
+
+ less: function(str){
+ var ret;
+ str = str.replace(/\\n/g, '\n');
+ require('less').render(str, function(err, css){
+ if (err) throw err;
+ ret = '<style>' + css.replace(/\n/g, '\\n') + '</style>';
+ });
+ return ret;
+ },
+
+ /**
+ * Transform markdown to html.
+ */
+
+ markdown: function(str){
+ var md;
+
+ // support markdown / discount
+ try {
+ md = require('markdown');
+ } catch (err){
+ try {
+ md = require('discount');
+ } catch (err) {
+ try {
+ md = require('markdown-js');
+ } catch (err) {
+ throw new Error('Cannot find markdown library, install markdown or discount');
+ }
+ }
+ }
+
+ str = str.replace(/\\n/g, '\n');
+ return md.parse(str).replace(/\n/g, '\\n').replace(/'/g,'&#39;');
+ },
+
+ /**
+ * Transform coffeescript to javascript.
+ */
+
+ coffeescript: function(str){
+ str = str.replace(/\\n/g, '\n');
+ var js = require('coffee-script').compile(str).replace(/\n/g, '\\n');
+ return '<script type="text/javascript">\\n' + js + '</script>';
+ }
+};
+}); // module: filters.js
+
+require.register("jade.js", function(module, exports, require){
+
+/*!
+ * Jade
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var Parser = require('./parser')
+ , Compiler = require('./compiler')
+
+/**
+ * Library version.
+ */
+
+exports.version = '0.12.1';
+
+/**
+ * Intermediate JavaScript cache.
+ */
+
+var cache = exports.cache = {};
+
+/**
+ * Expose self closing tags.
+ */
+
+exports.selfClosing = require('./self-closing');
+
+/**
+ * Default supported doctypes.
+ */
+
+exports.doctypes = require('./doctypes');
+
+/**
+ * Text filters.
+ */
+
+exports.filters = require('./filters');
+
+/**
+ * Utilities.
+ */
+
+exports.utils = require('./utils');
+
+/**
+ * Expose `Compiler`.
+ */
+
+exports.Compiler = Compiler;
+
+/**
+ * Expose `Parser`.
+ */
+
+exports.Parser = Parser;
+
+/**
+ * Nodes.
+ */
+
+exports.nodes = require('./nodes');
+
+/**
+ * Render the given attributes object.
+ *
+ * @param {Object} obj
+ * @return {String}
+ * @api private
+ */
+
+function attrs(obj){
+ var buf = []
+ , terse = obj.terse;
+ delete obj.terse;
+ var keys = Object.keys(obj)
+ , len = keys.length;
+ if (len) {
+ buf.push('');
+ for (var i = 0; i < len; ++i) {
+ var key = keys[i]
+ , val = obj[key];
+ if (typeof val === 'boolean' || val === '' || val == null) {
+ if (val) {
+ terse
+ ? buf.push(key)
+ : buf.push(key + '="' + key + '"');
+ }
+ } else {
+ buf.push(key + '="' + escape(val) + '"');
+ }
+ }
+ }
+ return buf.join(' ');
+}
+
+/**
+ * Escape the given string of `html`.
+ *
+ * @param {String} html
+ * @return {String}
+ * @api private
+ */
+
+function escape(html){
+ return String(html)
+ .replace(/&(?!\w+;)/g, '&amp;')
+ .replace(/</g, '&lt;')
+ .replace(/>/g, '&gt;')
+ .replace(/"/g, '&quot;');
+}
+
+/**
+ * Re-throw the given `err` in context to the
+ * `str` of jade, `filename`, and `lineno`.
+ *
+ * @param {Error} err
+ * @param {String} str
+ * @param {String} filename
+ * @param {String} lineno
+ * @api private
+ */
+
+function rethrow(err, str, filename, lineno){
+ var context = 3
+ , lines = str.split('\n')
+ , start = Math.max(lineno - context, 0)
+ , end = Math.min(lines.length, lineno + context);
+
+ // Error context
+ var context = lines.slice(start, end).map(function(line, i){
+ var curr = i + start + 1;
+ return (curr == lineno ? ' > ' : ' ')
+ + curr
+ + '| '
+ + line;
+ }).join('\n');
+
+ // Alter exception message
+ err.path = filename;
+ err.message = (filename || 'Jade') + ':' + lineno
+ + '\n' + context + '\n\n' + err.message;
+ throw err;
+}
+
+/**
+ * Parse the given `str` of jade and return a function body.
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {String}
+ * @api private
+ */
+
+function parse(str, options){
+ var filename = options.filename;
+ try {
+ // Parse
+ var parser = new Parser(str, filename);
+ if (options.debug) parser.debug();
+
+ // Compile
+ var compiler = new (options.compiler || Compiler)(parser.parse(), options)
+ , js = compiler.compile();
+
+ // Debug compiler
+ if (options.debug) {
+ console.log('\n\x1b[1mCompiled Function\x1b[0m:\n\n%s', js.replace(/^/gm, ' '));
+ }
+
+ try {
+ return ''
+ + attrs.toString() + '\n\n'
+ + escape.toString() + '\n\n'
+ + 'var buf = [];\n'
+ + (options.self
+ ? 'var self = locals || {}, __ = __ || locals.__;\n' + js
+ : 'with (locals || {}) {' + js + '}')
+ + 'return buf.join("");';
+ } catch (err) {
+ process.compile(js, filename || 'Jade');
+ return;
+ }
+ } catch (err) {
+ rethrow(err, str, filename, parser.lexer.lineno);
+ }
+}
+
+/**
+ * Compile a `Function` representation of the given jade `str`.
+ *
+ * @param {String} str
+ * @param {Options} options
+ * @return {Function}
+ * @api public
+ */
+
+exports.compile = function(str, options){
+ var options = options || {}
+ , input = JSON.stringify(str)
+ , filename = options.filename
+ ? JSON.stringify(options.filename)
+ : 'undefined';
+
+ // Reduce closure madness by injecting some locals
+ var fn = [
+ 'var __ = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };'
+ , rethrow.toString()
+ , 'try {'
+ , parse(String(str), options || {})
+ , '} catch (err) {'
+ , ' rethrow(err, __.input, __.filename, __.lineno);'
+ , '}'
+ ].join('\n');
+
+ return new Function('locals', fn);
+};
+
+/**
+ * Render the given `str` of jade.
+ *
+ * Options:
+ *
+ * - `scope` Evaluation scope (`this`)
+ * - `locals` Local variable object
+ * - `filename` Used in exceptions, and required by `cache`
+ * - `cache` Cache intermediate JavaScript in memory keyed by `filename`
+ * - `compiler` Compiler to replade jade's default
+ * - `doctype` Specify the default doctype
+ *
+ * @param {String|Buffer} str
+ * @param {Object} options
+ * @return {String}
+ * @api public
+ */
+
+exports.render = function(str, options){
+ var fn
+ , options = options || {}
+ , filename = options.filename;
+
+ // Accept Buffers
+ str = String(str);
+
+ // Cache support
+ if (options.cache) {
+ if (filename) {
+ if (cache[filename]) {
+ fn = cache[filename];
+ } else {
+ fn = cache[filename] = new Function('locals', parse(str, options));
+ }
+ } else {
+ throw new Error('filename is required when using the cache option');
+ }
+ } else {
+ fn = new Function('locals', parse(str, options));
+ }
+
+ // Render the template
+ try {
+ var locals = options.locals || {}
+ , meta = { lineno: 1 };
+ locals.__ = meta;
+ return fn.call(options.scope, locals);
+ } catch (err) {
+ rethrow(err, str, filename, meta.lineno);
+ }
+};
+
+/**
+ * Render jade template at the given `path`.
+ *
+ * @param {String} path
+ * @param {Object} options
+ * @param {Function} fn
+ * @api public
+ */
+
+exports.renderFile = function(path, options, fn){
+ var ret;
+
+ if (typeof options === 'function') {
+ fn = options;
+ options = {};
+ }
+ options.filename = path;
+
+ // Primed cache
+ if (options.cache && cache[path]) {
+ try {
+ ret = exports.render('', options);
+ } catch (err) {
+ return fn(err);
+ }
+ fn(null, ret);
+ } else {
+ fs.readFile(path, 'utf8', function(err, str){
+ if (err) return fn(err);
+ try {
+ ret = exports.render(str, options);
+ } catch (err) {
+ return fn(err);
+ }
+ fn(null, ret);
+ });
+ }
+};
+
+}); // module: jade.js
+
+require.register("lexer.js", function(module, exports, require){
+
+/*!
+ * Jade - Lexer
+ * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
+ * MIT Licensed
+ */
+
+/**
+ * Initialize `Lexer` with the given `str`.
+ *
+ * @param {String} str
+ * @api private
+ */
+
+var Lexer = module.exports = function Lexer(str) {
+ this.input = str.replace(/\r\n|\r/g, '\n');
+ this.deferredTokens = [];
+ this.lastIndents = 0;
+ this.lineno = 1;
+ this.stash = [];
+ this.indentStack = [];
+ this.indentRe = null;
+ this.pipeless = false;
+};
+
+/**
+ * Lexer prototype.
+ */
+
+Lexer.prototype = {
+
+ /**
+ * Construct a token with the given `type` and `val`.
+ *
+ * @param {String} type
+ * @param {String} val
+ * @return {Object}
+ * @api private
+ */
+
+ tok: function(type, val){
+ return {
+ type: type
+ , line: this.lineno
+ , val: val
+ }
+ },
+
+ /**
+ * Consume the given `len` of input.
+ *
+ * @param {Number} len
+ * @api private
+ */
+
+ consume: function(len){
+ this.input = this.input.substr(len);
+ },
+
+ /**
+ * Scan for `type` with the given `regexp`.
+ *
+ * @param {String} type
+ * @param {RegExp} regexp
+ * @return {Object}
+ * @api private
+ */
+
+ scan: function(regexp, type){
+ var captures;
+ if (captures = regexp.exec(this.input)) {
+ this.consume(captures[0].length);
+ return this.tok(type, captures[1]);
+ }
+ },
+
+ /**
+ * Defer the given `tok`.
+ *
+ * @param {Object} tok
+ * @api private
+ */
+
+ defer: function(tok){
+ this.deferredTokens.push(tok);
+ },
+
+ /**
+ * Lookahead `n` tokens.
+ *
+ * @param {Number} n
+ * @return {Object}
+ * @api private
+ */
+
+ lookahead: function(n){
+ var fetch = n - this.stash.length;
+ while (fetch-- > 0) this.stash.push(this.next());
+ return this.stash[--n];
+ },
+
+ /**
+ * Return the indexOf `start` / `end` delimiters.
+ *
+ * @param {String} start
+ * @param {String} end
+ * @return {Number}
+ * @api private
+ */
+
+ indexOfDelimiters: function(start, end){
+ var str = this.input
+ , nstart = 0
+ , nend = 0
+ , pos = 0;
+ for (var i = 0, len = str.length; i < len; ++i) {
+ if (start == str[i]) {
+ ++nstart;
+ } else if (end == str[i]) {
+ if (++nend == nstart) {
+ pos = i;
+ break;
+ }
+ }
+ }
+ return pos;
+ },
+
+ /**
+ * Stashed token.
+ */
+
+ stashed: function() {
+ return this.stash.length
+ && this.stash.shift();
+ },
+
+ /**
+ * Deferred token.
+ */
+
+ deferred: function() {
+ return this.deferredTokens.length
+ && this.deferredTokens.shift();
+ },
+
+ /**
+ * end-of-source.
+ */
+
+ eos: function() {
+ if (this.input.length) return;
+ if (this.indentStack.length) {
+ this.indentStack.shift();
+ return this.tok('outdent');
+ } else {
+ return this.tok('eos');
+ }
+ },
+
+ /**
+ * Block comment
+ */
+
+ blockComment: function() {
+ var captures;
+ if (captures = /^\/([^\n]+)/.exec(this.input)) {
+ this.consume(captures[0].length);
+ var tok = this.tok('block-comment', captures[1]);
+ return tok;
+ }
+ },
+
+ /**
+ * Comment.
+ */
+
+ comment: function() {
+ var captures;
+ if (captures = /^ *\/\/(-)?([^\n]+)/.exec(this.input)) {
+ this.consume(captures[0].length);
+ var tok = this.tok('comment', captures[2]);
+ tok.buffer = '-' != captures[1];
+ return tok;
+ }
+ },
+
+ /**
+ * Tag.
+ */
+
+ tag: function() {
+ var captures;
+ if (captures = /^(\w[-:\w]*)/.exec(this.input)) {
+ this.consume(captures[0].length);
+ var tok, name = captures[1];
+ if (':' == name[name.length - 1]) {
+ name = name.slice(0, -1);
+ tok = this.tok('tag', name);
+ this.deferredTokens.push(this.tok(':'));
+ while (' ' == this.input[0]) this.input = this.input.substr(1);
+ } else {
+ tok = this.tok('tag', name);
+ }
+ return tok;
+ }
+ },
+
+ /**
+ * Filter.
+ */
+
+ filter: function() {
+ return this.scan(/^:(\w+)/, 'filter');
+ },
+
+ /**
+ * Doctype.
+ */
+
+ doctype: function() {
+ return this.scan(/^(?:!!!|doctype) *(\w+)?/, 'doctype');
+ },
+
+ /**
+ * Id.
+ */
+
+ id: function() {
+ return this.scan(/^#([\w-]+)/, 'id');
+ },
+
+ /**
+ * Class.
+ */
+
+ className: function() {
+ return this.scan(/^\.([\w-]+)/, 'class');
+ },
+
+ /**
+ * Text.
+ */
+
+ text: function() {
+ return this.scan(/^(?:\| ?)?([^\n]+)/, 'text');
+ },
+
+ /**
+ * Each.
+ */
+
+ each: function() {
+ var captures;
+ if (captures = /^- *each *(\w+)(?: *, *(\w+))? * in *([^\n]+)/.exec(this.input)) {
+ this.consume(captures[0].length);
+ var tok = this.tok('each', captures[1]);
+ tok.key = captures[2] || 'index';
+ tok.code = captures[3];
+ return tok;
+ }
+ },
+
+ /**
+ * Code.
+ */
+
+ code: function() {
+ var captures;
+ if (captures = /^(!?=|-)([^\n]+)/.exec(this.input)) {
+ this.consume(captures[0].length);
+ var flags = captures[1];
+ captures[1] = captures[2];
+ var tok = this.tok('code', captures[1]);
+ tok.escape = flags[0] === '=';
+ tok.buffer = flags[0] === '=' || flags[1] === '=';
+ return tok;
+ }
+ },
+
+ /**
+ * Attributes.
+ */
+
+ attrs: function() {
+ if ('(' == this.input[0]) {
+ var index = this.indexOfDelimiters('(', ')')
+ , str = this.input.substr(1, index-1)
+ , tok = this.tok('attrs')
+ , len = str.length
+ , states = ['key']
+ , key = ''
+ , val = ''
+ , quote
+ , c;
+
+ function state(){
+ return states[states.length - 1];
+ }
+
+ function interpolate(attr) {
+ return attr.replace(/#\{([^}]+)\}/g, function(_, expr){
+ return quote + " + (" + expr + ") + " + quote;
+ });
+ }
+
+ this.consume(index + 1);
+ tok.attrs = {};
+
+ function parse(c) {
+ switch (c) {
+ case ',':
+ case '\n':
+ switch (state()) {
+ case 'expr':
+ case 'array':
+ case 'string':
+ case 'object':
+ val += c;
+ break;
+ default:
+ states.push('key');
+ val = val.trim();
+ key = key.trim();
+ if ('' == key) return;
+ tok.attrs[key.replace(/^['"]|['"]$/g, '')] = '' == val
+ ? true
+ : interpolate(val);
+ key = val = '';
+ }
+ break;
+ case '=':
+ switch (state()) {
+ case 'key char':
+ key += c;
+ break;
+ case 'val':
+ case 'expr':
+ case 'array':
+ case 'string':
+ case 'object':
+ val += c;
+ break;
+ default:
+ states.push('val');
+ }
+ break;
+ case '(':
+ if ('val' == state()) states.push('expr');
+ val += c;
+ break;
+ case ')':
+ if ('expr' == state()) states.pop();
+ val += c;
+ break;
+ case '{':
+ if ('val' == state()) states.push('object');
+ val += c;
+ break;
+ case '}':
+ if ('object' == state()) states.pop();
+ val += c;
+ break;
+ case '[':
+ if ('val' == state()) states.push('array');
+ val += c;
+ break;
+ case ']':
+ if ('array' == state()) states.pop();
+ val += c;
+ break;
+ case '"':
+ case "'":
+ switch (state()) {
+ case 'key':
+ states.push('key char');
+ break;
+ case 'key char':
+ states.pop();