document new filters

document new filters

# /api/App Components/Batman.View/Batman.View Filters

Batman filters are evaluated from left to right, with the output of each filter being injected into the next. This allows you to form filter chains for display purposes. Accessor caching does not apply to filter chains. If any component of the chain changes, the entire chain will be recalculated for each binding in the template.

Batman.js ships with many built-in view filters:

Type | Filters
---|----
__Logical Operators__ |  `and`, `or`, `not`
__Comparison Operators__ | `equals`, `eq`, `neq`, `lt`, `gt`, `lteq`, `gteq`
__General Utilities__ | `get`, `[]`, `meta`, `default`
__Number Helpers__ | `ceil`, `floor`, `round`, `precision`, `fixed`, `delimitNumber`, `ordinalize`
__Set Helpers__ |  `join`, `sort`, `map`, `has`, `first`, `toSentence`
__String Helpers__ | `interpolate`, `escape`, `capitalize`, `titleize`, `singularize`, `underscore`, `camelize`, `trim`, `raw`, `matches`, `truncate`, `prepend`, `append`, `replace`, `downcase`, `upcase`, `pluralize`, `humanize`
__Event Helpers__ | `withArguments`, `toggle`, `increment`, `decrement`
__Debuggers__ | `log`, `logStack`

## Custom Filters

You can define custom filters by setting them on the `Batman.Filters` object. For example, a batman.js view filter that formats a date with [moment.js](http://momentjs.com):

```coffeescript
# `moment` is the moment.js object
Batman.Filters.dateFormat = (date, format) ->
  moment(date).format(format)
```

You can also define custom filters when defining custom views with [`Batman.View.filter`](docs/api/batman.view.html#class_function_filter).

## equals(left, right) or eq(left, right): Boolean

Checks if left content is equal to right content:

```html
<span data-showif="title | equals 'Batman Views'"></span>
<span data-showif="value | eq 10"></span>
<span data-showif="value | eq true"></span>
```

__Note__: there is actually _one_ difference between `eq` and `equals`: `equals` rejects undefined values, but `eq` allows them.

## lt(left, right) : Boolean

Checks if left content is `less than` the right content.

```html
<span data-showif="posts.length | lt 10"></span>
```

## gt(left, right) : Boolean

Checks if left content is `greater than` the right content.

```html
<span data-showif="posts.length | gt 10"></span>
```

## lteq(left, right) : Boolean

Checks if left content is `less than or equal to` the right content.

```html
<span data-showif="posts.length | lteq 10"></span>
```

## gteq(left, right) : Boolean

Checks if left content is `greater than or equal to` the right content.

```html
<span data-showif="posts.length | gteq 10"></span>
```

## neq(left, right) : Boolean

Checks if left content is `is NOT equal to` the right content.

```html
<span data-showif="posts.length | neq 10"></span>
```

## ceil(value) : string

The `ceil` filter will run `Math.ceil` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | ceil"></span>
```

## floor(value) : string

The `floor` filter will run `Math.floor` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | floor"></span>
```

## round(value) : string

The `round` filter will run `Math.round` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | round"></span>
```

## percision(value, toPlace) : string

The `precision` filter will run `toPrecision()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | precision"></span>
<span data-bind="someValue | precision 3"></span>
```

## fixed(value, toPlace) : string

The `fixed` filter will run `toFixed()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | fixed"></span>
<span data-bind="someValue | fixed 3"></span>
```

## delimitNumber(value) : string

The `delimitNumber` filter will comma delimit a 'number'. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | delimitNumber"></span>
```

## raw(value) : string

The `raw` filter renders the unescaped value.

```html
<span data-bind="someHTMLyString | raw"></span>
```

## get(value, key) : value

Calls the get function on the input value with the specified key. Can be used with `Batman.Accessible` and `Batman.TerminalAccessible`:

```html
<span data-bind="accessibleFunction | get 'item'"></span>
```

## value[key] : value

Shorthand for the `get` filter.

## and(inputValue, otherValue) : boolean

Returns `true` if `inputValue` and `otherValue` are truthy:

```html
<p data-showif='post.published | and currentUser.loggedIn'></p>
```

## or(inputValue, otherValue) : boolean

Returns `true` if either `inputValue` or `otherValue` are truthy:

```html
<p data-showif='post.published | or currentUser.isAdmin'></p>
```

## not(value) : boolean

Inverts the truthiness of the input value:

```html
<span data-hideif="title | equals 'Batman Views' | not | and action | equals 'show'"></span>
```

## matches(value, string) : boolean

Tests a string against the input value:

```html
<span data-showif="title | matches 'Bat'"></span>
```

## truncate(value, length, end = '...') : string

Limits the length of output to the specified length and appends the specified text if over the limit:

```html
<span data-bind="page.title | truncate 5, '…'"></span>
```
Would result in:
```html
<span data-bind="page.title | truncate 5, '…'">About…</span>
```

## default(value, defaultValue) : value

Provides a default value if the keypath is falsy:

```html
<input type="text" data-bind="page.title | default 'About Us'"></input>
```

## prepend(value, string) : string

Prepends the string to the input value:

```html
<span data-bind-class="page.tag | prepend 'ico-'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | prepend 'ico-'" class="ico-about"></span>
```

## append(value, string) : string

Appends the string to the input value:

```html
<span data-bind-class="page.tag | append '-ico'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | append '-ico'" class="about-ico"></span>
```

## replace(value, searchString, replaceString[, flags]) : string

Replaces content in the input value matching the `searchString` with the `replaceString` value:

```html
<span data-bind="page.title | replace 'html', 'HTML'"></span>
```

## downcase(value) : string

Downcases the input value:

```html
<span data-bind="page.title | downcase"></span>
```

## upcase(value) : string

Upcases the input value:

```html
<span data-bind="page.title | upcase"></span>
```

## pluralize(value, count, includeCount[=true]) : string

Pluralizes the input value based on the patterns specified in `Batman.helpers.inflector` and the count provided:

```coffeescript
( ->
  @singular /(analysis)$/i, '$1'
  @singular /(analy)ses$/i, '$1sis'
).call(Batman.helpers.inflector)
```

```html
<span data-bind="'analysis' | pluralize page.comments.count"></span>
```

## singularize(string) : string

Returns the singular inflection of `string`.

## humanize(string) : string

Takes a string and makes it human readable, for example 'an_underscored_string' would become 'An underscored string'.

```html
<span data-bind="'about_us_page' | humanize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | humanize">About us page</span>
```

## titleize(value) : string

Humanizes `string` and capitalizes each word. For example,

```html
<span data-bind="'about_us_page' | titleize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | titleize">About Us Page</span>
```

## underscore(string) : string

Converts `string` to underscore case.

## camelize(string, firstLetterLower[=false]) : string

Converts `string` to camel case. if `firstLetterLower` is true, the first letter will be lowercase.

## ordinalize(numberOrString) : string

Turns `numberOrString` into an ordinalized number, for example, `4 | ordinalize` becomes `4th`.

## join(array, separator = '') : string

Joins `array` into a single string with `separator`:

```html
<span data-bind="page.comments | map 'title' | join ', '"></span>
```

## toSentence(array) : string

Joins `array` with `, ` and ` and`, as appropriate. See [helpers.toSentence](/docs/api/batman.helpers.html#class_function_tosentence).

## sort(value) : value

Sorts an `array` using the default comparison:

```html
<span data-foreach-comment="page.comments | sort" data-bind="comment.title"><span>
```

## map(iterable) : value

Maps the specified keypath from an `array` of objects:

```html
<span data-foreach-author="page.comments | map 'author'" data-bind="author"><span>
```

## has(iterable, item) : boolean

Calls the `iterable`'s `has` function to check for the existence of the specified `item`.

```coffeescript
class Sample.FirstController extends Batman.Controller
  index: ->
    @set('things', new Batman.Set('thing1', 'thing2'))
```

```html
<input type="checkbox" data-bind-checked="things | has 'thing1'"></input>
```
If you were to dispatch `first#index`:
```html
<input type="checkbox" data-bind-checked="things | has 'thing1'" checked="true"></input>
```

## first(iterable) : value

Returns the first value from an `array`:

```html
<span data-context-firstComment="page.comments | first"></span>
```

## meta(value, keypath) : value

Looks up `keypath` on `value.meta`. The `value` must have a `meta` property to look up against.

## interpolate(string, valuesObject) : string

Allows you to use string interpolation:

```html
<span data-bind="'The page title is %{title}' | interpolate {'title': 'page.title'}"></span>
```

## withArguments(function, curriedArguments...) : function

Ensures that the function is called with the supplied arguments in addition to the arguments it would normally be called with. This is a form of currying. The argument order will be the curried arguments (those passed to withArguments) first, then the regular arguments. In the case of a click event, the regular arguments are node, event, view.

```coffeescript
class Sample.CloseWindowView extends Batman.View
  html: '<span data-event-click="closeWindow | withArguments true"></span>'

  closeWindow: (actuallyClose) ->
    window.close() if actuallyClose
```

```html
<div data-view="CloseWindowView"></div>
```

## escape(value) : string

Escapes HTML in the input value:

```html
<textarea data-bind="page.body_html | escape"></textarea>
```

## toggle(keypath) : function

Returns a handler for toggling `keypath`. Clicking this button will toggle `showMeMore` between `true` and `false`:

```html
<button data-event-click='showMeMore | toggle'></button>
```

## increment(keypath, change[=1]) : function

Returns a handler that increments `keypath` by `change`. If `keypath` 's value isn't set, it will be treated as 0.

```html
<button data-event-click='totalScore | increment'>Add 1</button>
```

## decrement(keypath, change[=1]) : function

Returns a handler that decrements `keypath` by `change`. If `keypath` 's value isn't set, it will be treated as 0.

```html
<button data-event-click='totalScore | decrement 3'>Subtract 3</button>
```

# /api/App Components/Batman.View/Batman.View Filters

Batman filters are evaluated from left to right, with the output of each filter being injected into the next. This allows you to form filter chains for display purposes. Accessor caching does not apply to filter chains. If any component of the chain changes, the entire chain will be recalculated for each binding in the template.

Batman.js ships with many built-in view filters:

Type | Filters
---|----
__Logical Operators__ |  `and`, `or`, `not`
__Comparison Operators__ | `equals`, `eq`, `neq`, `lt`, `gt`, `lteq`, `gteq`
__General Utilities__ | `get`, `[]`, `meta`, `withArguments`, `default`
__Number Helpers__ | `ceil`, `floor`, `round`, `precision`, `fixed`, `delimitNumber`, `ordinalize`
__Set Helpers__ |  `join`, `sort`, `map`, `has`, `first`, `toSentence`
__String Helpers__ | `interpolate`, `escape`, `capitalize`, `titleize`, `singularize`, `underscore`, `camelize`, `trim`, `raw`, `matches`, `truncate`, `prepend`, `append`, `replace`, `downcase`, `upcase`, `pluralize`, `humanize`
__Debuggers__ | `log`, `logStack`

## Custom Filters

You can define custom filters by setting them on the `Batman.Filters` object. For example, a batman.js view filter that formats a date with [moment.js](http://momentjs.com):

```coffeescript
# `moment` is the moment.js object
Batman.Filters.dateFormat = (date, format) ->
  moment(date).format(format)
```

You can also define custom filters when defining custom views with [`Batman.View.filter`](docs/api/batman.view.html#class_function_filter).

## equals(left, right) or eq(left, right): Boolean

Checks if left content is equal to right content:

```html
<span data-showif="title | equals 'Batman Views'"></span>
<span data-showif="value | eq 10"></span>
<span data-showif="value | eq true"></span>
```

__Note__: there is actually _one_ difference between `eq` and `equals`: `equals` rejects undefined values, but `eq` allows them.

## lt(left, right) : Boolean

Checks if left content is `less than` the right content.

```html
<span data-showif="posts.length | lt 10"></span>
```

## gt(left, right) : Boolean

Checks if left content is `greater than` the right content.

```html
<span data-showif="posts.length | gt 10"></span>
```

## lteq(left, right) : Boolean

Checks if left content is `less than or equal to` the right content.

```html
<span data-showif="posts.length | lteq 10"></span>
```

## gteq(left, right) : Boolean

Checks if left content is `greater than or equal to` the right content.

```html
<span data-showif="posts.length | gteq 10"></span>
```

## neq(left, right) : Boolean

Checks if left content is `is NOT equal to` the right content.

```html
<span data-showif="posts.length | neq 10"></span>
```

## ceil(value) : string

The `ceil` filter will run `Math.ceil` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | ceil"></span>
```

## floor(value) : string

The `floor` filter will run `Math.floor` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | floor"></span>
```

## round(value) : string

The `round` filter will run `Math.round` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | round"></span>
```

## percision(value, toPlace) : string

The `precision` filter will run `toPrecision()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | precision"></span>
<span data-bind="someValue | precision 3"></span>
```

## fixed(value, toPlace) : string

The `fixed` filter will run `toFixed()` on the input value. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | fixed"></span>
<span data-bind="someValue | fixed 3"></span>
```

## delimitNumber(value) : string

The `delimitNumber` filter will comma delimit a 'number'. Value can be either a `string` or `integer`

```html
<span data-bind="someValue | delimitNumber"></span>
```

## raw(value) : string

The `raw` filter renders the unescaped value.

```html
<span data-bind="someHTMLyString | raw"></span>
```

## get(value, key) : value

Calls the get function on the input value with the specified key. Can be used with `Batman.Accessible` and `Batman.TerminalAccessible`:

```html
<span data-bind="accessibleFunction | get 'item'"></span>
```

## value[key] : value

Shorthand for the `get` filter.

## and(inputValue, otherValue) : boolean

Returns `true` if `inputValue` and `otherValue` are truthy:

```html
<p data-showif='post.published | and currentUser.loggedIn'></p>
```

## or(inputValue, otherValue) : boolean

Returns `true` if either `inputValue` or `otherValue` are truthy:

```html
<p data-showif='post.published | or currentUser.isAdmin'></p>
```

## not(value) : boolean

Inverts the truthiness of the input value:

```html
<span data-hideif="title | equals 'Batman Views' | not | and action | equals 'show'"></span>
```

## matches(value, string) : boolean

Tests a string against the input value:

```html
<span data-showif="title | matches 'Bat'"></span>
```

## truncate(value, length, end = '...') : string

Limits the length of output to the specified length and appends the specified text if over the limit:

```html
<span data-bind="page.title | truncate 5, '…'"></span>
```
Would result in:
```html
<span data-bind="page.title | truncate 5, '…'">About…</span>
```

## default(value, defaultValue) : value

Provides a default value if the keypath is falsy:

```html
<input type="text" data-bind="page.title | default 'About Us'"></input>
```

## prepend(value, string) : string

Prepends the string to the input value:

```html
<span data-bind-class="page.tag | prepend 'ico-'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | prepend 'ico-'" class="ico-about"></span>
```

## append(value, string) : string

Appends the string to the input value:

```html
<span data-bind-class="page.tag | append '-ico'"></span>
```
If page.tag is 'about' this would result in:
```html
<span data-bind-class="page.tag | append '-ico'" class="about-ico"></span>
```

## replace(value, searchString, replaceString[, flags]) : string

Replaces content in the input value matching the `searchString` with the `replaceString` value:

```html
<span data-bind="page.title | replace 'html', 'HTML'"></span>
```

## downcase(value) : string

Downcases the input value:

```html
<span data-bind="page.title | downcase"></span>
```

## upcase(value) : string

Upcases the input value:

```html
<span data-bind="page.title | upcase"></span>
```

## pluralize(value, count, includeCount[=true]) : string

Pluralizes the input value based on the patterns specified in `Batman.helpers.inflector` and the count provided:

```coffeescript
( ->
  @singular /(analysis)$/i, '$1'
  @singular /(analy)ses$/i, '$1sis'
).call(Batman.helpers.inflector)
```

```html
<span data-bind="'analysis' | pluralize page.comments.count"></span>
```

## singularize(string) : string

Returns the singular inflection of `string`.

## humanize(string) : string

Takes a string and makes it human readable, for example 'an_underscored_string' would become 'An underscored string'.

```html
<span data-bind="'about_us_page' | humanize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | humanize">About us page</span>
```

## titleize(value) : string

Humanizes `string` and capitalizes each word. For example,

```html
<span data-bind="'about_us_page' | titleize"></span>
```
Would result in:
```html
<span data-bind="'about_us_page' | titleize">About Us Page</span>
```

## underscore(string) : string

Converts `string` to underscore case.

## camelize(string, firstLetterLower[=false]) : string

Converts `string` to camel case. if `firstLetterLower` is true, the first letter will be lowercase.

## ordinalize(numberOrString) : string

Turns `numberOrString` into an ordinalized number, for example, `4 | ordinalize` becomes `4th`.

## join(array, separator = '') : string

Joins `array` into a single string with `separator`:

```html
<span data-bind="page.comments | map 'title' | join ', '"></span>
```

## toSentence(array) : string

Joins `array` with `, ` and ` and`, as appropriate. See [helpers.toSentence](/docs/api/batman.helpers.html#class_function_tosentence).

## sort(value) : value

Sorts an `array` using the default comparison:

```html
<span data-foreach-comment="page.comments | sort" data-bind="comment.title"><span>
```

## map(iterable) : value

Maps the specified keypath from an `array` of objects:

```html
<span data-foreach-author="page.comments | map 'author'" data-bind="author"><span>
```

## has(iterable, item) : boolean

Calls the `iterable`'s `has` function to check for the existence of the specified `item`.

```coffeescript
class Sample.FirstController extends Batman.Controller
  index: ->
    @set('things', new Batman.Set('thing1', 'thing2'))
```

```html
<input type="checkbox" data-bind-checked="things | has 'thing1'"></input>
```
If you were to dispatch `first#index`:
```html
<input type="checkbox" data-bind-checked="things | has 'thing1'" checked="true"></input>
```

## first(iterable) : value

Returns the first value from an `array`:

```html
<span data-context-firstComment="page.comments | first"></span>
```

## meta(value, keypath) : value

Looks up `keypath` on `value.meta`. The `value` must have a `meta` property to look up against.

## interpolate(string, valuesObject) : string

Allows you to use string interpolation:

```html
<span data-bind="'The page title is %{title}' | interpolate {'title': 'page.title'}"></span>
```

## withArguments(function, curriedArguments...) : function

Ensures that the function is called with the supplied arguments in addition to the arguments it would normally be called with. This is a form of currying. The argument order will be the curried arguments (those passed to withArguments) first, then the regular arguments. In the case of a click event, the regular arguments are node, event, view.

```coffeescript
class Sample.CloseWindowView extends Batman.View
  html: '<span data-event-click="closeWindow | withArguments true"></span>'

  closeWindow: (actuallyClose) ->
    window.close() if actuallyClose
```

```html
<div data-view="CloseWindowView"></div>
```

## escape(value) : string

Escapes HTML in the input value:

```html
<textarea data-bind="page.body_html | escape"></textarea>
```


Close #2 - Measure image processing time

    url          = require 'url'

    compression  = require 'compression'
    express      = require 'express'
    morgan       = require 'morgan'
    responseTime = require 'response-time'

    multer       = require 'multer'
    async        = require 'async'
    dms2dec      = require 'dms2dec'

    raven        = require 'raven'
    sentry       = require './sentry'
    librato      = require './librato'

    app = express()
    app.use morgan 'combined'
    app.use compression()
    app.use responseTime()

    Upload = require 's3-uploader'
    s3 = new Upload process.env.AWS_BUCKET_NAME,
      awsBucketRegion: process.env.AWS_BUCKET_REGION
      awsBucketPath: process.env.AWS_BUCKET_PATH
      awsBucketAcl: 'public-read'
      awsHttpTimeout: 60000
      returnExif: true

      versions: [{
        original: true
        awsImageAcl: 'private'
      },{
        suffix: '-large'
        quality: 80
        maxHeight: 1040
        maxWidth: 1040
      },{
        suffix: '-medium'
        maxHeight: 780
        maxWidth: 780
      },{
        suffix: '-small'
        maxHeight: 320
        maxWidth: 320
      }]

    origins = process.env.ALLOW_ORIGINS?.split(',') or []

    app.all '/upload', (req, res, next) ->
      res.once 'close', -> sentry.captureResClose res

      origin = url.parse req.get('Origin') or ''

      if origin.hostname not in origins
        error = new Error "Bad Origin Header #{req.get('Origin')}"
        error.status = 403
        return next error

      res.set 'Access-Control-Allow-Origin', req.get('Origin')
      res.set 'Access-Control-Allow-Methods', 'POST'
      res.set 'Access-Control-Allow-Headers', 'X-Requested-With, Content-Type'
      res.set 'Access-Control-Expose-Headers', 'X-Response-Time'
      res.set 'Access-Control-Allow-Max-Age', 0

      return res.send 200 if req.method is 'OPTIONS'
      return next()

    app.post '/upload', multer(dest: require('os').tmpdir()), (req, res, next) ->
      librato.measure 'image.upload', Object.keys(req.files).length, {}

      async.mapSeries Object.keys(req.files), (key, cb) ->
        if req.files[key].extension.toLowerCase() not in ['jpg', 'jpeg', 'png', 'gif']
          error = new Error "Invalid Image #{req.files[key].extension}"
          error.status = 422
          return cb error

        t1 = new Date().getTime()
        s3.upload req.files[key].path, {}, (err, images, meta) ->
          return cb err if err

          librato.logImageProcessingTime t1, new Date().getTime()

          if meta.exif['exif:GPSLatitude'] and meta.exif['exif:GPSLongitude']
            meta.geojson =
              type: 'Point'
              coordinates: dms2dec \
                meta.exif['exif:GPSLatitude'], \
                meta.exif['exif:GPSLatitudeRef'], \
                meta.exif['exif:GPSLongitude'], \
                meta.exif['exif:GPSLongitudeRef']
              .reverse()

          return cb null, versions: images.splice(1), meta: meta
      , (err, files) ->
        return next err if err
        sentry.captureHeaderSent req, files if res._headerSent
        return res.status(201).json files

    app.use (req, res, next) ->
      res.status(404).json message: 'Not Found'

    app.use raven.middleware.express sentry
    app.use (err, req, res, next) ->
      if not err.status or err.status >= 500
        sentry.captureError err

        console.error err.message
        console.error err.stack

        res.status(err.status or 500).json message: 'Internal Server Error'
      else
        sentry.captureMessage err.message, level: 'warning', req: req
        res.status(err.status).json message: err.message

    if not module.parent
      app.listen process.env.PORT_WWW
      console.log "Server listening on port #{process.env.PORT_WWW}"
    else
      module.exports = app

    url          = require 'url'

    compression  = require 'compression'
    express      = require 'express'
    morgan       = require 'morgan'
    responseTime = require 'response-time'

    multer       = require 'multer'
    async        = require 'async'
    dms2dec      = require 'dms2dec'

    raven        = require 'raven'
    sentry       = require './sentry'
    librato      = require './librato'

    app = express()
    app.use morgan 'combined'
    app.use compression()
    app.use responseTime()

    Upload = require 's3-uploader'
    s3 = new Upload process.env.AWS_BUCKET_NAME,
      awsBucketRegion: process.env.AWS_BUCKET_REGION
      awsBucketPath: process.env.AWS_BUCKET_PATH
      awsBucketAcl: 'public-read'
      awsHttpTimeout: 60000
      returnExif: true

      versions: [{
        original: true
        awsImageAcl: 'private'
      },{
        suffix: '-large'
        quality: 80
        maxHeight: 1040
        maxWidth: 1040
      },{
        suffix: '-medium'
        maxHeight: 780
        maxWidth: 780
      },{
        suffix: '-small'
        maxHeight: 320
        maxWidth: 320
      }]

    origins = process.env.ALLOW_ORIGINS?.split(',') or []

    app.all '/upload', (req, res, next) ->
      res.once 'close', -> sentry.captureResClose res

      origin = url.parse req.get('Origin') or ''

      if origin.hostname not in origins
        error = new Error "Bad Origin Header #{req.get('Origin')}"
        error.status = 403
        return next error

      res.set 'Access-Control-Allow-Origin', req.get('Origin')
      res.set 'Access-Control-Allow-Methods', 'POST'
      res.set 'Access-Control-Allow-Headers', 'X-Requested-With, Content-Type'
      res.set 'Access-Control-Expose-Headers', 'X-Response-Time'
      res.set 'Access-Control-Allow-Max-Age', 0

      return res.send 200 if req.method is 'OPTIONS'
      return next()

    app.post '/upload', multer(dest: require('os').tmpdir()), (req, res, next) ->
      librato.measure 'image.upload', Object.keys(req.files).length, {}

      async.mapSeries Object.keys(req.files), (key, cb) ->
        if req.files[key].extension.toLowerCase() not in ['jpg', 'jpeg', 'png', 'gif']
          error = new Error "Invalid Image #{req.files[key].extension}"
          error.status = 422
          return cb error

        s3.upload req.files[key].path, {}, (err, images, meta) ->
          return cb err if err

          if meta.exif['exif:GPSLatitude'] and meta.exif['exif:GPSLongitude']
            meta.geojson =
              type: 'Point'
              coordinates: dms2dec \
                meta.exif['exif:GPSLatitude'], \
                meta.exif['exif:GPSLatitudeRef'], \
                meta.exif['exif:GPSLongitude'], \
                meta.exif['exif:GPSLongitudeRef']
              .reverse()

          return cb null, versions: images.splice(1), meta: meta
      , (err, files) ->
        return next err if err
        sentry.captureHeaderSent req, files if res._headerSent
        return res.status(201).json files

    app.use (req, res, next) ->
      res.status(404).json message: 'Not Found'

    app.use raven.middleware.express sentry
    app.use (err, req, res, next) ->
      if not err.status or err.status >= 500
        sentry.captureError err

        console.error err.message
        console.error err.stack

        res.status(err.status or 500).json message: 'Internal Server Error'
      else
        sentry.captureMessage err.message, level: 'warning', req: req
        res.status(err.status).json message: err.message

    if not module.parent
      app.listen process.env.PORT_WWW
      console.log "Server listening on port #{process.env.PORT_WWW}"
    else
      module.exports = app


doc cleanup

doc cleanup

# Batman.DOM

Batman includes some helper methods to assist in DOM manipulation.

The following are included in the platform adapters:
 - `querySelector`
 - `querySelectorAll`
 - `destroyNode`
 - `setInnerHTML`
 - `textContent`
 - `addEventListener`
 - `removeEventListener`

## @scrollIntoView(elementID : string)
Scrolls the desired element into view.  If the element isn't there or
doesn't have a `scrollIntoView` method this will fail silently.

## @setStyleProperty(node : Node,property : string,value : string, importance : string)
Sets the style property or attribute on the supplied node.  This method will prefer `setProperty` over `setAttribute`.

	test "setStyleProperty", ->
	  node = document.createElement('div')
	  Batman.DOM.setStyleProperty( node, "color", "white", "important")
	  equal node.style.getPropertyValue("color"), "white"
	  equal "important", node.style.getPropertyPriority("color")

## @valueForNode(node: Node [, value = '',escapeValue = true ]) : string
Gets the value of a node and optionally sets it as well.  `escapeValue` will escape the value via `Batman.escapeHTML`

	test 'valueForNode', ->
	  node = document.createElement('input')
	  val = Batman.DOM.valueForNode(node, 'stuff' )
	  equal val, "stuff"
	  equal node.value, "stuff"

## @nodeIsEditable(node) : boolean
Returns whether a node is editable or not.

	test 'nodeIsEditable', ->
	  node = document.createElement('div')
	  ok !Batman.DOM.nodeIsEditable(node)
	  node = document.createElement('input')
	  ok Batman.DOM.nodeIsEditable(node)

## @addEventListener(node : Node, eventName : string, callback : function)
Adds the event listener, uses the platform `addEventListener` if available otherwise use `attachEvent on{eventName}`
Batman stores the listeners internally.

	test 'addEventListener', 1, ->
	  node = document.createElement('div')
	  Batman.DOM.addEventListener( node, 'click', -> ok true )
	  node.dispatchEvent(new Event('click'))

## @removeEventListener(node : Node, eventName : string, callback : function)
Removes the event listener from the node and removes any internal references to it.

## @cleanupNode(node : Node)
Removes all the event listeners from the specified node and any child nodes.

## .hasAddEventListener : boolean
Returns the whether the `window` object contains addEventListener.

	test "does the window have an event listener", ->
	  ok Batman.DOM.hasAddEventListener

## @preventDefault(e : Event)
Prevents the default event from happening.  If preventDefault isn't a `function` then it will set the `returnValue` to false

	test "preventDefault", ->
	  e = { returnValue: true }
	  Batman.DOM.preventDefault(e)
	  ok !e.returnValue

	  e = { preventDefault: -> ok true }
	  Batman.DOM.preventDefault(e)

## @stopPropagation(e : Event)
Stops the event from propogating.  If the stopPropgation isn't a `function` then it will set `cancelBubble` to true

	test "stopPropagation", ->
	  e = { cancelBubble: false }
	  Batman.DOM.stopPropagation(e)
	  ok e.cancelBubble

	  e = {stopPropagation: -> ok true }
	  Batman.DOM.stopPropagation(e)

### The following methods are only available with the jQuery platform or a polyfill

## @querySelectorAll(node : Node, selector : string)
Performs a jQuery like selector depending on your platform

## @querySelector(node : Node, selector : string)
Performs a jQuery like selector that returns one element

## @destroyNode(node : Node)
Calls `Batman.DOM.cleanupNode` and  removes node and anything inside from the document tree.

	test 'destroyNode', ->
	  node1 = document.createElement('div')
	  node2 = document.createElement('div')
	  node3 = document.createElement('div')
	  node1.appendChild(node2)
	  node2.appendChild(node3)

	  Batman.DOM.destroyNode( node1 )
	  equal node1.childNodes.length, 1

## @setInnerHtml(node : Node, html : string)
Set an element's content and any content that was in that element is completely replaced by the new content.
_note_ this can't be used on XML documents.

	test "innerHTML", ->
	  node = document.createElement('div')
	  Batman.DOM.setInnerHTML(node, "FOO")
	  equal node.innerHTML, "FOO"

## @textContent(node) : string
Returns the string of the text contained in the node.

	test "textContent", ->
	  node = document.createElement('div')
	  content = document.createTextNode("FOO")
	  node.appendChild(content)
	  equal Batman.DOM.textContent(node), "FOO"

# Batman.DOM

Batman includes some helper methods to assist in DOM manipulation.

The following are included in the platform adapters:
 - `querySelector`
 - `querySelectorAll`
 - `destroyNode`
 - `setInnerHTML`
 - `textContent`
 - `addEventListener`
 - `removeEventListener`

## @scrollIntoView (elementID)
Scrolls the desired element into view.  If the element isn't there or
doesn't have a `scrollIntoView` method this will fail silently.

## @setStyleProperty ( node : Node, property : String, value : String, importance : String )
Sets the style property or attribute on the supplied node.  This method will prefer `setProperty` over `setAttribute`.

    test "setStyleProperty", ->
      node = document.createElement('div')
      Batman.DOM.setStyleProperty( node, "color", "white", "important")
      equal node.style.getPropertyValue("color"), "white"
      equal "important", node.style.getPropertyPriority("color")

## @valueForNode ( node: Node, [ value = '', escapeValue = true ] )
Gets the value of a node and optionally sets it as well.  `escapeValue` will escape the value via `Batman.escapeHTML`

    test 'valueForNode', ->
      node = document.createElement('input')
      val = Batman.DOM.valueForNode(node, 'stuff' )
      equal val, "stuff"
      equal node.value, "stuff"

## @nodeIsEditable ( node )
Returns whether a node is editable or not.

    test 'nodeIsEditable', ->
      node = document.createElement('div')
      ok !Batman.DOM.nodeIsEditable(node)
      node = document.createElement('input')
      ok Batman.DOM.nodeIsEditable(node)

## @addEventListener ( node, eventName, callback )
Adds the event listener, uses the platform `addEventListener` if available otherwise use `attachEvent on{eventName}`
Batman stores the listeners internally.

    test 'addEventListener', 1, ->
      node = document.createElement('div')
      Batman.DOM.addEventListener( node, 'click', -> ok true )
      node.dispatchEvent(new Event('click'))

## @removeEventListener( node, eventName, callback )
Removes the event listener from the node and removes any internal references to it.

## @cleanupNode (node)
Removes all the event listeners from the specified node and any child nodes.

## @hasAddEventListener
Returns the whether the `window` object contains addEventListener.

    test "does the window have an event listener", ->
      ok Batman.DOM.hasAddEventListener

## @preventDefault ( e : Event )
Prevents the default event from happening.  If preventDefault isn't a `function` then it will set the `returnValue` to false

    test "preventDefault", ->
      e = { returnValue: true }
      Batman.DOM.preventDefault(e)
      ok !e.returnValue

      e = { preventDefault: -> ok true }
      Batman.DOM.preventDefault(e)

## @ stopPropagation ( e : Event )
Stops the event from propogating.  If the stopPropgation isn't a `function` then it will set `cancelBubble` to true

    test "stopPropagation", ->
      e = { cancelBubble: false }
      Batman.DOM.stopPropagation(e)
      ok e.cancelBubble

      e = {stopPropagation: -> ok true }
      Batman.DOM.stopPropagation(e)

### The following methods are only available with the jQuery platform or a polyfill

## @querySelectorAll (node, selector)
Performs a jQuery like selector depending on your platform

## @querySelector (node, selector )
Performs a jQuery like selector that returns one element

## @destroyNode (node)
Calls `Batman.DOM.cleanupNode` and  removes node and anything inside from the document tree.

    test 'destroyNode', ->
      node1 = document.createElement('div')
      node2 = document.createElement('div')
      node3 = document.createElement('div')
      node1.appendChild(node2)
      node2.appendChild(node3)

      Batman.DOM.destroyNode( node1 )
      equal node1.childNodes.length, 1

## @setInnerHtml (node, html)
Set an element's content and any content that was in that element is completely replaced by the new content.
_note_ this can't be used on XML documents.

    test "innerHTML", ->
      node = document.createElement('div')
      Batman.DOM.setInnerHTML(node, "FOO")
      equal node.innerHTML, "FOO"

## @textContent ( node )
Returns the string of the text contained in the node.

    test "textContent", ->
      node = document.createElement('div')
      content = document.createTextNode("FOO")
      node.appendChild(content)
      equal Batman.DOM.textContent(node), "FOO"


Fix incorrect collection cursor count

Fix incorrect collection cursor count

    MongoQS     = require 'mongo-querystring'
    Document    = require './model/Document'
    stringify   = require('JSONStream').stringify

    sentry      = require './db/sentry'
    mongo       = require './db/mongo'

    collections = [
      'turer'
      'steder'
      'grupper'
      'områder'
      'bilder'
      'arrangementer'
    ]

    qs = new MongoQS
      alias:
        tag: 'tags.0'
        gruppe: 'grupper'
        endret: 'after'
      ignore:
        api_key     : true # other use
        order       : true # reserved
        sort        : true # other use
        limit       : true # other use
        skip        : true # other use
        fields      : true # other use
        _id         : true # use API endpoint
      custom:
        bbox: 'geojson'
        near: 'geojson'
        after: 'endret'

## PARAM {collection}

    exports.param = (req, res, next, col) ->
      if col not in collections
        return res.json 404, message: "Type #{col} not found"

      req.type = col
      req.db   = col: mongo[col], query: {}

      next()

    exports.paramCol2 = (req, res, next, col2) ->
      if col not in collections
        return res.json 404, message: "Type #{col2} not found"

      req.type      = col2
      req.db.col    = mongo[col2]
      req.db.query  = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

      next()

## OPTIONS /{collection}

    exports.options = (req, res, next) ->
      res.setHeader 'Access-Control-Expose-Headers', [
        'ETag', 'Location', 'Last-Modified', 'Count-Return', 'Count-Total'
      ].join(', ')
      res.setHeader 'Access-Control-Max-Age', 86400
      res.setHeader 'Access-Control-Allow-Headers', 'Content-Type'
      res.setHeader 'Access-Control-Allow-Methods', 'HEAD, GET, POST'
      res.send 204

## HEAD /{collection}
## GET /{collection}

    exports.get = (req, res, next) ->

### Query

      req.db.query = qs.parse req.query

Prevent private documents for other API user from being returned when quering
`tilbyder` and `status` fields.

      for key, val of req.query
        switch key
          when 'status'
            req.db.query.tilbyder = req.user.tilbyder if val not in ['Offentlig', 'Slettet']
            break
          when 'tilbyder'
            req.db.query.status = 'Offentlig' if val isnt req.user.tilbyder
            break
          else
            if key.substr(0,6) is 'privat'
              req.db.query.tilbyder = req.user.tilbyder
              break

Apply default access control unless `status` or `tilbyder` fields are already
queried.

      if not req.db.query.tilbyder or req.db.query.status
        req.db.query.$or = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

### Fields

Always return `lisens` and `tilbyder` fields for propper attribution. Document
ObjectID is always returned by MongoDB.

      fields = lisens: true, tilbyder: true

Parse user specified fields to be returned.

      if typeof req.query.fields is 'string' and req.query.fields
        for field in req.query.fields.split ',' when field.substr(0,6) isnt 'privat'
          fields[field] = true

Default fields if unless specified by the user.

      else
        fields.endret = true
        fields.status = true
        fields.navn = true
        fields.tags = true

### Sort

Limit sort to ascending or descending on `endret` and `navn` since they are
indexed, non-indexed fields could be slower.

      if typeof req.query.sort is 'string' and req.query.sort
        sort = switch req.query.sort
          when 'endret' then [['endret', 1]]
          when '-endret' then [['endret', -1]]
          when 'navn' then [['navn', 1]]
          when '-navn' then [['navn', -1]]
          else 'endret'

Only apply default sort if there are no geospatial queries.

      else
        sort = 'endret' if not req.db.query.geojson

### Execute

Set limit, skip and, sort options for documents to be returned.

      options =
        limit: Math.min((parseInt(req.query.limit, 10) or 20), 50)
        skip: parseInt(req.query.skip, 10) or 0
        sort: sort

      cursor = req.db.col.find(req.db.query, fields, options)

Count number of matching documents in MongoDB database.

      cursor.count false, (err, total) ->
        return next err if err

Calculate the total number of documents that will eventually be returned (not
the total number of matching documents) since we don't know that in advanced
(due to the nature of streaming).

        count = Math.min(options.limit, Math.max(total - options.skip, 0))

Set `Count-Return` and `Count-Total` headers so that one can use a `HEAD` query
to look up the number of matched documents for a query without the documents
them selves. This may be useful for statistics purposes.

        res.set 'Count-Return', count
        res.set 'Count-Total', total

Return to the user if this is a `HEAD` query or there are no matching documents.

        return res.send 204 if req.method is 'HEAD'
        return res.json documents: [], count: 0, total: 0 if total is 0

Stream matching documents in order to prevent loading them into memory.

        res.set 'Content-Type', 'application/json; charset=utf-8'

        op = '{"documents":['
        cl = '],"count":' + count + ',"total":' + total + '}'

        cursor.stream().pipe(stringify(op, ',', cl)).pipe(res)

## POST /{collection}

    exports.post = (req, res, next) ->
      return res.json 400, message: 'Body is missing' if Object.keys(req.body).length is 0
      return res.json 422, message: 'Body should be a JSON Hash' if req.body instanceof Array

      req.body.tilbyder = req.user.tilbyder

      new Document(req.type, null).once('error', next).once 'ready', ->
        @insert req.body, (err, warn, data) ->
          if err
            return next(err) if err.name isnt 'ValidationError'

            sentry.captureDocumentError req, err

            return res.json 422,
              document: req.body
              message: 'Validation Failed'
              errors: err.details #TODO(starefossen) document this

          res.set 'ETag', "\"#{data.checksum}\""
          res.set 'Last-Modified', new Date(data.endret).toUTCString()
          # res.set 'Location', req.get 'host'

          return res.json 201,
            document: data
            message: 'Validation Warnings' if warn.length > 0
            warnings: warn if warn.length > 0

    MongoQS     = require 'mongo-querystring'
    Document    = require './model/Document'
    stringify   = require('JSONStream').stringify

    sentry      = require './db/sentry'
    mongo       = require './db/mongo'

    collections = [
      'turer'
      'steder'
      'grupper'
      'områder'
      'bilder'
      'arrangementer'
    ]

    qs = new MongoQS
      alias:
        tag: 'tags.0'
        gruppe: 'grupper'
        endret: 'after'
      ignore:
        api_key     : true # other use
        order       : true # reserved
        sort        : true # other use
        limit       : true # other use
        skip        : true # other use
        fields      : true # other use
        _id         : true # use API endpoint
      custom:
        bbox: 'geojson'
        near: 'geojson'
        after: 'endret'

## PARAM {collection}

    exports.param = (req, res, next, col) ->
      if col not in collections
        return res.json 404, message: "Type #{col} not found"

      req.type = col
      req.db   = col: mongo[col], query: {}

      next()

    exports.paramCol2 = (req, res, next, col2) ->
      if col not in collections
        return res.json 404, message: "Type #{col2} not found"

      req.type      = col2
      req.db.col    = mongo[col2]
      req.db.query  = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

      next()

## OPTIONS /{collection}

    exports.options = (req, res, next) ->
      res.setHeader 'Access-Control-Expose-Headers', [
        'ETag', 'Location', 'Last-Modified', 'Count-Return', 'Count-Total'
      ].join(', ')
      res.setHeader 'Access-Control-Max-Age', 86400
      res.setHeader 'Access-Control-Allow-Headers', 'Content-Type'
      res.setHeader 'Access-Control-Allow-Methods', 'HEAD, GET, POST'
      res.send 204

## HEAD /{collection}
## GET /{collection}

    exports.get = (req, res, next) ->

### Query

      req.db.query = qs.parse req.query

Prevent private documents for other API user from being returned when quering
`tilbyder` and `status` fields.

      for key, val of req.query
        switch key
          when 'status'
            req.db.query.tilbyder = req.user.tilbyder if val not in ['Offentlig', 'Slettet']
            break
          when 'tilbyder'
            req.db.query.status = 'Offentlig' if val isnt req.user.tilbyder
            break
          else
            if key.substr(0,6) is 'privat'
              req.db.query.tilbyder = req.user.tilbyder
              break

Apply default access control unless `status` or `tilbyder` fields are already
queried.

      if not req.db.query.tilbyder or req.db.query.status
        req.db.query.$or = [{status: 'Offentlig'}, {tilbyder: req.user.tilbyder}]

### Fields

Always return `lisens` and `tilbyder` fields for propper attribution. Document
ObjectID is always returned by MongoDB.

      fields = lisens: true, tilbyder: true

Parse user specified fields to be returned.

      if typeof req.query.fields is 'string' and req.query.fields
        for field in req.query.fields.split ',' when field.substr(0,6) isnt 'privat'
          fields[field] = true

Default fields if unless specified by the user.

      else
        fields.endret = true
        fields.status = true
        fields.navn = true
        fields.tags = true

### Sort

Limit sort to ascending or descending on `endret` and `navn` since they are
indexed, non-indexed fields could be slower.

      if typeof req.query.sort is 'string' and req.query.sort
        sort = switch req.query.sort
          when 'endret' then [['endret', 1]]
          when '-endret' then [['endret', -1]]
          when 'navn' then [['navn', 1]]
          when '-navn' then [['navn', -1]]
          else 'endret'

Only apply default sort if there are no geospatial queries.

      else
        sort = 'endret' if not req.db.query.geojson

### Execute

      options =
        limit: Math.min((parseInt(req.query.limit, 10) or 20), 50)
        skip: parseInt(req.query.skip, 10) or 0
        sort: sort

Retrive matching documents from MongoDB.

      cursor = req.db.col.find(req.db.query, fields, options)
      cursor.count (err, total) ->
        return next err if err
        res.set 'Count-Return', Math.min(options.limit, total)
        res.set 'Count-Total', total
        return res.send 204 if req.method is 'HEAD'
        return res.json documents: [], count: 0, total: 0 if total is 0
        res.set 'Content-Type', 'application/json; charset=utf-8'

Calculate number of rows returned since we don't know that in advanced (due to
the nature of streaming).

        count = Math.min(options.limit, Math.max(total - options.skip, 0))

Stream documents user in order to prevent loading them into memory.

        op = '{"documents":['
        cl = '],"count":' + count + ',"total":' + total + '}'

        cursor.stream().pipe(stringify(op, ',', cl)).pipe(res)

## POST /{collection}

    exports.post = (req, res, next) ->
      return res.json 400, message: 'Body is missing' if Object.keys(req.body).length is 0
      return res.json 422, message: 'Body should be a JSON Hash' if req.body instanceof Array

      req.body.tilbyder = req.user.tilbyder

      new Document(req.type, null).once('error', next).once 'ready', ->
        @insert req.body, (err, warn, data) ->
          if err
            return next(err) if err.name isnt 'ValidationError'

            sentry.captureDocumentError req, err

            return res.json 422,
              document: req.body
              message: 'Validation Failed'
              errors: err.details #TODO(starefossen) document this

          res.set 'ETag', "\"#{data.checksum}\""
          res.set 'Last-Modified', new Date(data.endret).toUTCString()
          # res.set 'Location', req.get 'host'

          return res.json 201,
            document: data
            message: 'Validation Warnings' if warn.length > 0
            warnings: warn if warn.length > 0


NativeItem auto size on browser bug fixed

# Native

    'use strict'

    utils = require 'src/utils'
    log = require 'src/log'
    assert = require 'src/assert'
    colorUtils = require 'src/renderer/utils/color'

    IS_NATIVE = not utils.isServer and not utils.isBrowser

    if IS_NATIVE
        nativeBridge = require 'src/native'

    module.exports = (Renderer, Impl, itemUtils) ->

        class Native extends Renderer.Item
            @__name__ = 'Native'
            @__path__ = 'Renderer.Native'

## *Native* Native.New([*Component* component, *Object* options])

            @New = (component, opts) ->
                item = new @
                itemUtils.Object.initialize item, component, opts
                unless IS_NATIVE
                    item.onParentChange Impl.updateNativeSize
                @Initialize? item
                item

## Native.defineProperty(*Object* config)

Defines new property with the given name.

For each property, signal `onXYZChange` is created,
where `XYZ` is the given name.

`config` parameter must be an object with specified keys:
- `enabled` - whether it's supported on current platform,
- `name` - name of the property,
- `type` - type of predefined condifuration described below,
- `defaultValue`,
- `setter`,
- `getter`,
- `developmentSetter`
- `implementationValue` - function returning value passed to the implementation.

### Predefined types

            PROPERTY_TYPES = Object.create null

#### text

            PROPERTY_TYPES.text = ->
                defaultValue: ''
                developmentSetter: (val) ->
                    assert.isString val

#### number

            PROPERTY_TYPES.number = ->
                defaultValue: 0
                developmentSetter: (val) ->
                    assert.isFloat val

#### boolean

            PROPERTY_TYPES.boolean = ->
                defaultValue: false
                developmentSetter: (val) ->
                    assert.isBoolean val

#### color

            PROPERTY_TYPES.color = (config) ->
                defaultValue: ''
                developmentSetter: (val) ->
                    assert.isString val
                implementationValue: do ->
                    RESOURCE_REQUEST =
                        property: 'color'
                    (val) ->
                        val = Renderer.resources?.resolve(val, RESOURCE_REQUEST) or val
                        if IS_NATIVE
                            if val?
                                colorUtils.toRGBAHex val, config.defaultValue
                            else
                                null
                        else
                            val

#### item

            PROPERTY_TYPES.item = (config) ->
                defaultValue: null
                developmentSetter: (val) ->
                    if val?
                        assert.instanceOf val, Renderer.Item
                implementationValue: (val) ->
                    if IS_NATIVE
                        if val?
                            val._impl.id
                        else
                            null
                    else
                        val

            @defineProperty = (config) ->
                itemName = @__name__
                properties = @_properties ||= []
                config = utils.clone config

                assert.isString itemName, '''
                    NativeItem.__name__ unique name must be specified
                '''
                assert.isObject config, '''
                    NativeItem.defineProperty config parameter must be an object
                '''
                assert.isString config.name, '''
                    NativeItem property name must be a string
                '''
                assert.isNotDefined properties[config.name], """
                    Property #{config.name} is already defined
                """
                assert.isDefined PROPERTY_TYPES[config.type], """
                    Unknown property type #{config.type}
                """ if config.type

                # type
                if typeConfigFunc = PROPERTY_TYPES[config.type]
                    typeConfig = typeConfigFunc(config)
                    for key, val of typeConfig
                        if key not of config
                            config[key] = val

                # constructor
                config.constructor = @

                # internalName
                config.internalName = itemUtils.getPropInternalName config.name

                # implementation
                config.implementation = do ->
                    if config.enabled is false
                        return utils.NOP

                    ctorName = utils.capitalize itemName
                    name = utils.capitalize config.name
                    if IS_NATIVE
                        funcName = "rendererSet#{ctorName}#{name}"
                        (val) ->
                            nativeBridge.callFunction funcName, @_impl.id, val
                    else
                        funcName = "set#{ctorName}#{name}"
                        (val) ->
                            Impl[funcName]?.call @, val

                # save
                properties.push config

                # create
                itemUtils.defineProperty config

## *Native* Native::constructor() : *Item*

            constructor: ->
                super()

                unless IS_NATIVE
                    @_autoWidth = true
                    @_autoHeight = true
                    @_width = -1
                    @_height = -1

                # save properties with default values
                if properties = @constructor._properties
                    for property in properties
                        @[property.internalName] = property.defaultValue

            unless IS_NATIVE
                _width: -1
                getter = utils.lookupGetter @::, 'width'
                itemWidthSetter = utils.lookupSetter @::, 'width'
                utils.defineProperty @::, 'width', null, getter,
                    do (_super = itemWidthSetter) -> (val) ->
                        if @_autoWidth = val is -1
                            Impl.updateNativeSize.call @
                        else
                            _super.call @, val
                        return

                _height: -1
                getter = utils.lookupGetter @::, 'height'
                itemHeightSetter = utils.lookupSetter @::, 'height'
                utils.defineProperty @::, 'height', null, getter,
                    do (_super = itemHeightSetter) -> (val) ->
                        if @_autoHeight = val is -1
                            Impl.updateNativeSize.call @
                        else
                            _super.call @, val
                        return

## Native::set(*String* propName, *Any* val)

            set: (name, val) ->
                assert.isString name, "NativeItem.set name must be a string, but #{name} given"

                ctorName = utils.capitalize @constructor.__name__
                id = @_impl.id
                name = utils.capitalize name

                if IS_NATIVE
                    funcName = "rendererSet#{ctorName}#{name}"
                    nativeBridge.callFunction funcName, id, val
                else
                    funcName = "set#{ctorName}#{name}"
                    Impl[funcName]?.call @, val
                return

## Native::call(*String* funcName, *Any* args...)

            call: (name, args...) ->
                assert.isString name, "NativeItem.call name must be a string, but #{name} given"

                ctorName = utils.capitalize @constructor.__name__
                id = @_impl.id
                name = utils.capitalize name

                if IS_NATIVE
                    funcName = "rendererCall#{ctorName}#{name}"
                    callArgs = [funcName, id, args...]
                    nativeBridge.callFunction.apply nativeBridge, callArgs
                else
                    funcName = "call#{ctorName}#{name}"
                    Impl[funcName]?.apply @, args
                return

## Native::on(*String* eventName, *Function* listener)

            # nativeEventName -> item id -> [item, listeners...]
            eventListeners = Object.create null

            createNativeEventListener = (listeners, eventName) -> (id) ->
                unless itemListeners = listeners[id]
                    log.warn "Got a native event '#{eventName}' for an item which " +
                        "didn't register a listener on this event; check if you " +
                        "properly call 'on()' method with a signal listener"
                    return

                length = arguments.length
                args = new Array length - 1
                for i in [0...length - 1] by 1
                    args[i] = arguments[i + 1]

                item = itemListeners[0]
                for i in [1...itemListeners.length] by 1
                    itemListeners[i].apply item, args

                return

            on: (name, func) ->
                assert.isString name, "NativeItem.on name must be a string, but #{name} given"
                assert.isFunction func, """
                    NativeItem.on listener must be a function, but #{func} given
                """

                name = utils.capitalize name

                if IS_NATIVE
                    ctorName = utils.capitalize @constructor.__name__
                    eventName = "rendererOn#{ctorName}#{name}"

                    unless listeners = eventListeners[eventName]
                        listeners = eventListeners[eventName] = Object.create(null)
                        nativeBridge.on eventName, createNativeEventListener(listeners, eventName)

                    itemListeners = listeners[@_impl.id] ?= [@]
                    itemListeners.push func
                else
                    eventName = "on#{name}"
                    @_impl[eventName]?.connect func
                return

        Native

# Native

    'use strict'

    utils = require 'src/utils'
    log = require 'src/log'
    assert = require 'src/assert'
    colorUtils = require 'src/renderer/utils/color'

    IS_NATIVE = not utils.isServer and not utils.isBrowser

    if IS_NATIVE
        nativeBridge = require 'src/native'

    module.exports = (Renderer, Impl, itemUtils) ->

        class Native extends Renderer.Item
            @__name__ = 'Native'
            @__path__ = 'Renderer.Native'

## *Native* Native.New([*Component* component, *Object* options])

            @New = (component, opts) ->
                item = new @
                itemUtils.Object.initialize item, component, opts
                unless IS_NATIVE
                    item.onParentChange Impl.updateNativeSize
                @Initialize? item
                item

## Native.defineProperty(*Object* config)

Defines new property with the given name.

For each property, signal `onXYZChange` is created,
where `XYZ` is the given name.

`config` parameter must be an object with specified keys:
- `enabled` - whether it's supported on current platform,
- `name` - name of the property,
- `type` - type of predefined condifuration described below,
- `defaultValue`,
- `setter`,
- `getter`,
- `developmentSetter`
- `implementationValue` - function returning value passed to the implementation.

### Predefined types

            PROPERTY_TYPES = Object.create null

#### text

            PROPERTY_TYPES.text = ->
                defaultValue: ''
                developmentSetter: (val) ->
                    assert.isString val

#### number

            PROPERTY_TYPES.number = ->
                defaultValue: 0
                developmentSetter: (val) ->
                    assert.isFloat val

#### boolean

            PROPERTY_TYPES.boolean = ->
                defaultValue: false
                developmentSetter: (val) ->
                    assert.isBoolean val

#### color

            PROPERTY_TYPES.color = (config) ->
                defaultValue: ''
                developmentSetter: (val) ->
                    assert.isString val
                implementationValue: do ->
                    RESOURCE_REQUEST =
                        property: 'color'
                    (val) ->
                        val = Renderer.resources?.resolve(val, RESOURCE_REQUEST) or val
                        if IS_NATIVE
                            if val?
                                colorUtils.toRGBAHex val, config.defaultValue
                            else
                                null
                        else
                            val

#### item

            PROPERTY_TYPES.item = (config) ->
                defaultValue: null
                developmentSetter: (val) ->
                    if val?
                        assert.instanceOf val, Renderer.Item
                implementationValue: (val) ->
                    if IS_NATIVE
                        if val?
                            val._impl.id
                        else
                            null
                    else
                        val

            @defineProperty = (config) ->
                itemName = @__name__
                properties = @_properties ||= []
                config = utils.clone config

                assert.isString itemName, '''
                    NativeItem.__name__ unique name must be specified
                '''
                assert.isObject config, '''
                    NativeItem.defineProperty config parameter must be an object
                '''
                assert.isString config.name, '''
                    NativeItem property name must be a string
                '''
                assert.isNotDefined properties[config.name], """
                    Property #{config.name} is already defined
                """
                assert.isDefined PROPERTY_TYPES[config.type], """
                    Unknown property type #{config.type}
                """ if config.type

                # type
                if typeConfigFunc = PROPERTY_TYPES[config.type]
                    typeConfig = typeConfigFunc(config)
                    for key, val of typeConfig
                        if key not of config
                            config[key] = val

                # constructor
                config.constructor = @

                # internalName
                config.internalName = itemUtils.getPropInternalName config.name

                # implementation
                config.implementation = do ->
                    if config.enabled is false
                        return utils.NOP

                    ctorName = utils.capitalize itemName
                    name = utils.capitalize config.name
                    if IS_NATIVE
                        funcName = "rendererSet#{ctorName}#{name}"
                        (val) ->
                            nativeBridge.callFunction funcName, @_impl.id, val
                    else
                        funcName = "set#{ctorName}#{name}"
                        (val) ->
                            Impl[funcName]?.call @, val

                # save
                properties.push config

                # create
                itemUtils.defineProperty config

## *Native* Native::constructor() : *Item*

            constructor: ->
                super()

                unless IS_NATIVE
                    @_autoWidth = true
                    @_autoHeight = true
                    @_width = -1
                    @_height = -1

                # save properties with default values
                if properties = @constructor._properties
                    for property in properties
                        @[property.internalName] = property.defaultValue

            unless IS_NATIVE
                _width: -1
                getter = utils.lookupGetter @::, 'width'
                itemWidthSetter = utils.lookupSetter @::, 'width'
                utils.defineProperty @::, 'width', null, getter,
                    do (_super = itemWidthSetter) -> (val) ->
                        if @_autoWidth = val is -1
                            _super.call @, @_contentWidth
                            Impl.updateNativeSize.call @
                        else
                            _super.call @, val
                        return

                _height: -1
                getter = utils.lookupGetter @::, 'height'
                itemHeightSetter = utils.lookupSetter @::, 'height'
                utils.defineProperty @::, 'height', null, getter,
                    do (_super = itemHeightSetter) -> (val) ->
                        if @_autoHeight = val is -1
                            _super.call @, @_contentHeight
                            Impl.updateNativeSize.call @
                        else
                            _super.call @, val
                        return

## Native::set(*String* propName, *Any* val)

            set: (name, val) ->
                assert.isString name, "NativeItem.set name must be a string, but #{name} given"

                ctorName = utils.capitalize @constructor.__name__
                id = @_impl.id
                name = utils.capitalize name

                if IS_NATIVE
                    funcName = "rendererSet#{ctorName}#{name}"
                    nativeBridge.callFunction funcName, id, val
                else
                    funcName = "set#{ctorName}#{name}"
                    Impl[funcName]?.call @, val
                return

## Native::call(*String* funcName, *Any* args...)

            call: (name, args...) ->
                assert.isString name, "NativeItem.call name must be a string, but #{name} given"

                ctorName = utils.capitalize @constructor.__name__
                id = @_impl.id
                name = utils.capitalize name

                if IS_NATIVE
                    funcName = "rendererCall#{ctorName}#{name}"
                    callArgs = [funcName, id, args...]
                    nativeBridge.callFunction.apply nativeBridge, callArgs
                else
                    funcName = "call#{ctorName}#{name}"
                    Impl[funcName]?.apply @, args
                return

## Native::on(*String* eventName, *Function* listener)

            # nativeEventName -> item id -> [item, listeners...]
            eventListeners = Object.create null

            createNativeEventListener = (listeners, eventName) -> (id) ->
                unless itemListeners = listeners[id]
                    log.warn "Got a native event '#{eventName}' for an item which " +
                        "didn't register a listener on this event; check if you " +
                        "properly call 'on()' method with a signal listener"
                    return

                length = arguments.length
                args = new Array length - 1
                for i in [0...length - 1] by 1
                    args[i] = arguments[i + 1]

                item = itemListeners[0]
                for i in [1...itemListeners.length] by 1
                    itemListeners[i].apply item, args

                return

            on: (name, func) ->
                assert.isString name, "NativeItem.on name must be a string, but #{name} given"
                assert.isFunction func, """
                    NativeItem.on listener must be a function, but #{func} given
                """

                name = utils.capitalize name

                if IS_NATIVE
                    ctorName = utils.capitalize @constructor.__name__
                    eventName = "rendererOn#{ctorName}#{name}"

                    unless listeners = eventListeners[eventName]
                        listeners = eventListeners[eventName] = Object.create(null)
                        nativeBridge.on eventName, createNativeEventListener(listeners, eventName)

                    itemListeners = listeners[@_impl.id] ?= [@]
                    itemListeners.push func
                else
                    eventName = "on#{name}"
                    @_impl[eventName]?.connect func
                return

        Native


New prefixes for method signatures

New prefixes for method signatures

# Batman.Controller

`Batman.Controller` is the base class from which all an application's controllers should descend from. `Batman.Controller`s are responsible for executing _actions_ which fire off requests for model data, render views, or redirect to other actions in response to navigation state changes.

## Controller Directory

`Batman.Controller`s are singletons which means each controller in your application is instantiated exactly once. The instance of each controller is available on the class at the `@sharedController` property, or within a `ControllerDirectory` on the `Application` class. See `Batman.Application.controllers`.

## Actions

Each `Batman.Controller` should have a number of instance level functions which can fetch the data needed and often render a view (or views) to display that data. These functions can be declared in typical CoffeeScript fashion like so:

    class Alfred extends Batman.App
      @root "todos#index"

    class Alfred.TodosController extends Batman.Controller
      index: (params) ->
      show: (params) ->

Each action function receives the parameters from the dispatcher which are pulled out of the navigated-to URL. This includes both named route parameters (`/:foo` style) as well as arbitrary query parameters (`?foo=bar` style).

## routingKey and Minification

For functionality like contextual redirects and automatic view source and class inference, Batman needs to know the name of all your `Controller` subclasses. The usual way to do this is by using `Function::name` which Batman will use in development, but this is often mangled in minified production environments. For this reason, Batman will error out on boot if a `Controller` subclass' `routingKey` is not defined on the prototype. The `routingKey` is a `String` which remains unmangled after minification and thus allows Batman to continue using the aforementioned features. To disable this requirement (if you know your code won't ever be minified), set `Batman.config.minificationErrors` to false.

## ::render([options : [Object|boolean]])

`render` is used to control the rendering of the currently executed action. Passing `false` will prevent the current action from implicitly rendering the view. Passing an `options` object allows the default `view`, `source`, `viewClass` or `yield` block to be overridden, all of which are optional. If no parameters are passed to options, it will manually trigger the render function, rather than waiting for it to be implicitly called at the end of the action.

_Note_: For more information on yield blocks, see Controller::.defaultRenderYield

    class TestController extends Batman.Controller
      routingKey: 'test'

      nonVisibleAction: ->
        @render(false)

      customSource: ->
        @render(source: 'errors/404')

      customYield: ->
        @render(into: 'not-main')

      delayedRender: ->
        setTimeout (-> @render()), 1000
        @render(false)

## @beforeAction([options : [string|Object],] filter : [string|Function])

`@beforeAction` allows controllers to declare that a function should be executed before the body of an action during action execution. `@beforeAction` optionally accepts some options representing which action(s) to execute the filter before, and then a string naming a function or function proper to execute.

The `options` argument can take three forms to imply different things:

 1. `undefined`: implies that this filter function should be executed before all actions.
 2. a String: implies that this filter function should be executed before the action named by the string.
 3. an Object: implies that this filter function should be executed before the actions named by an Array at the `only` key in the options object, or before all actions excluding those named by an Array at the `except` key in the options object.

    test "@beforeAction allows declaration of filters to execute before an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "index", -> results.push "before!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "before!"
      equal results[1], "action!"

    test "@beforeAction allows declaration of named filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "show", "fetchTodo"
        fetchTodo: -> @set("todo", {isDone: true})
        show: ->
          @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "show"
      deepEqual controller.get("todo"), {isDone: true}

    test "@beforeAction allows whitelisting or blacklisting filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: ["show", "edit"], "fetchTodo"
        @beforeAction except: ["index"], "prepareNewTodo"
        fetchTodo: -> @set "todo", {isDone: true}
        prepareNewTodo: -> @set "newTodo", {isDone: false}
        index: -> @render false
        show: -> @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "show"
      deepEqual controller.get("todo"), {isDone: true}
      deepEqual controller.get("newTodo"), {isDone: false}

    test "@beforeAction allows declaration of filters to execute before all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction -> results.push "before!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "before!"
      equal results[1], "action!"

## @afterAction([options : [string|Object],] filter : [string|Function])

`@afterAction` allows controllers to declare that a function should be run after the action body and all operations have completed during action execution. Functions declared by `@afterAction` will thus be run after the code of the action body and also after any redirects or renders have taken place and completed. `@afterAction` optionally accepts some options representing which action(s) to execute the filter after, and then a string naming a function or function proper to execute. See `Batman.Controller.beforeAction` for documentation on the structure of the options.

    test "@afterAction allows declaration of filters to execute after an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @afterAction only: "index", -> results.push "after!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "action!"
      equal results[1], "after!"

    test "@afterAction allows declaration of named filters to execute after an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: "test"
        @afterAction only: "create", "notify"
        notify: -> result = "Todo created successfully."
        create: -> @render false

      controller = TodoController.get("sharedController")
      controller.dispatch "create"
      equal result, "Todo created successfully."

    test "@afterAction allows whitelisting or blacklisting filters to execute after an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: "test"
        @afterAction only: ["create", "update"], "notify"
        index: -> @render false
        create: -> @render false
        notify: -> result = "Todo created successfully."

      controller = TodoController.get("sharedController")
      controller.dispatch "index"
      equal result, null
      controller.dispatch "create"
      equal result, "Todo created successfully."

    test "@afterAction allows declaration of filters to execute after all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @afterAction -> results.push "after!"
        index: ->
          results.push "action!"
          @render false

      controller = TestController.get("sharedController")
      controller.dispatch "index"
      equal results[0], "action!"
      equal results[1], "after!"

## ::executeAction(action: string[, params: Object])

`executeAction` will run the `action` specified, running all `@beforeAction` and `@afterAction` filters that match that endpoint. Optionally, `params` can be passed into the new action for processing. If no params are passed, it will default to the params of the current action.

    test "executeAction will run the called action", ->
      result = null

      class TestController extends Batman.Controller
        routingKey: "test"
        show: (params) ->
          result = params.id
          @render false
        other: ->
          @executeAction("show", {id: 4})

      controller = TestController.get("sharedController")
      controller.dispatch "other"
      equal result, 4

    test "executeAction will run all @beforeAction and @afterAction filters", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: "test"
        @beforeAction only: "index", -> results.push "before!"
        @afterAction only: "index", -> results.push "after!"
        index: ->
          results.push "action!"
          @render false
        other: ->
          @executeAction("index")

      controller = TestController.get("sharedController")
      controller.dispatch "other"
      deepEqual results, ["before!", "action!", "after!"]

## ::redirect(url: string)

`redirect` will forward the user to a new route defined by `url` without hard-refreshing the page. This modifies the current page URL using pushState if supported, otherwise falling back to hash-bang fragment identifiers. The url can be obtained dynamically using `MyApp.get('routes').myResourceName().path()` or by manually passing a string, such as `@redirect('/test')`.

## ::scrollToHash([hash: string])

`scrollToHash` emulates the native scrolling behaviour of the browser by allowing the URL to link to a specific ID on the page. The code will look for an element with a matching ID to `hash` if it is provided otherwise using the `#` parameter in the URL. If an element is found, the page will scroll to the matching element.

## ::.autoScrollToHash[= true] : boolean

`autoScrollToHash` is a boolean property on the instance level of a controller describing whether or not the controller should automatically scroll the browser window to the element with ID equal to the `hash` parameter. This behaviour emulates the native behaviour of the same nature, but is implemented in Batman so the functionality works after each dispatch (instead of each page refresh) and when Batman is using hash bang routing. `autoScrollToHash` is true by default.

## ::.defaultRenderYield[= 'main'] : string

`defaultRenderYield` is a `string` representing which yield a controller should automatically render into if no yield is mentioned explicitly. `defaultRenderYield` is `'main'` normally, which means calls to `@render()` or actions which rely on the implicit rendering render their views into the `main` yield (and end up wherever `data-yield="main"` is found in your HTML).

# Batman.Controller

`Batman.Controller` is the base class from which all an application's controllers should descend from. `Batman.Controllers` are responsible for executing _actions_ which fire off requests for model data, render views, or redirect to other actions in response to navigation state changes.

## Controller Directory

`Batman.Controller`s are singletons which means each controller in your application is instantiated exactly once. The instance of each controller is available on the class at the `@sharedContoller` property, or within a `ControllerDirectory` on the `Application` class. See `Batman.Application.controllers`.

## Actions

Each `Batman.Controller` should have a number of instance level functions which can fetch the data needed and often render a view (or views) to display that data. These functions can be declared in typical CoffeeScript fashion like so:

```coffeescript
class Alfred.TodosController

  index: (params) ->

  show: (params) ->
```

Each action function receives the parameters from the dispatcher which are pulled out of the navigated-to URL. This includes both named route parameters (`/:foo` style) as well as arbitrary query paramters (`?foo=bar` style).

## `routingKey` and Minification

For functionality like contextual redirects and automatic view source and class inference, Batman needs to know the name of all your `Controller` subclasses. The usual way to do this is by using `Function::name` which Batman will use in development, but this is often mangled in minified production environments. For this reason, Batman will error out on boot if a `Controller` subclass' `routingKey` is not defined on the prototype. The `routingKey` is a `String` which remains unmangled after minification and thus allows Batman to continue using the aforementioned features. To disable this requirement (if you know your code won't ever be minified), set `Batman.config.minificationErrors` to false.

## @beforeAction([options : [String|Object]], filter : [String|Function])

`@beforeAction` allows controllers to declare that a function should be executed before the body of an action during action execution. `@beforeAction` optionally accepts some options representing which action(s) to execute the filter before, and then a string naming a function or function proper to execute.

The `options` argument can take three forms to imply different things:

 1. `undefined`: implies that this filter function should be executed before all actions.
 2. a String: implies that this filter function should be executed before the action named by the string.
 3. an Object: implies that this filter function should be executed before the actions named by an Array at the `only` key in the options object, or before all actions excluding those named by an Array at the `except` key in the options object.

    test "@beforeAction allows declaration of filters to execute before an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: 'test'
        @beforeAction only: 'index', -> results.push 'before!'
        index: ->
          results.push 'action!'
          @render false

      controller = TestController.get('sharedController')
      controller.dispatch 'index'
      equal results[0], 'before!'
      equal results[1], 'action!'

    test "@beforeAction allows declaration of named filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: 'test'
        @beforeAction only: 'show', 'fetchTodo'
        fetchTodo: -> @set 'todo', {isDone: true}
        show: ->
          @render false

      controller = TodoController.get('sharedController')
      controller.dispatch 'show'
      deepEqual controller.get('todo'), {isDone: true}

    test "@beforeAction allows whitelisting or blacklisting filters to execute before an action", ->
      class TodoController extends Batman.Controller
        routingKey: 'test'
        @beforeAction only: ['show', 'edit'], 'fetchTodo'
        @beforeAction except: ['index'], 'prepareNewTodo'
        fetchTodo: -> @set 'todo', {isDone: true}
        prepareNewTodo: -> @set 'newTodo', {isDone: false}
        index: -> @render false
        show: -> @render false

      controller = TodoController.get('sharedController')
      controller.dispatch 'show'
      deepEqual controller.get('todo'), {isDone: true}
      deepEqual controller.get('newTodo'), {isDone: false}

    test "@beforeAction allows declaration of filters to execute before all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: 'test'
        @beforeAction -> results.push 'before!'
        index: ->
          results.push 'action!'
          @render false

      controller = TestController.get('sharedController')
      controller.dispatch 'index'
      equal results[0], 'before!'
      equal results[1], 'action!'

## @afterAction([options : [String|Object]], filter : [String|Function])

`@afterAction` allows controllers to declare that a function should be run after the action body and all operations have completed during action execution. Functions declared by `@afterAction` will thus be run after the code of the action body and also after any redirects or renders have taken place and completed. `@beforeAction` optionally accepts some options representing which action(s) to execute the filter before, and then a string naming a function or function proper to execute. See `Batman.Controller.beforeAction` for documentation on the structure of the options.

    test "@afterAction allows declaration of filters to execute before an action", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: 'test'
        @afterAction only: 'index', -> results.push 'after!'
        index: ->
          results.push 'action!'
          @render false

      controller = TestController.get('sharedController')
      controller.dispatch 'index'
      equal results[0], 'action!'
      equal results[1], 'after!'

    test "@afterAction allows declaration of named filters to execute before an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: 'test'
        @afterAction only: 'create', 'notify'
        create: -> @render false
        notify: -> result = "Todo created successfully."

      controller = TodoController.get('sharedController')
      controller.dispatch 'create'
      equal result, 'Todo created successfully.'

    test "@afterAction allows whitelisting or blacklisting filters to execute before an action", ->
      result = null

      class TodoController extends Batman.Controller
        routingKey: 'test'
        @afterAction {only: ['create', 'update']}, 'notify'
        index: -> @render false
        create: -> @render false
        notify: -> result = "Todo created successfully."

      controller = TodoController.get('sharedController')
      controller.dispatch 'index'
      equal result, null
      controller.dispatch 'create'
      equal result, 'Todo created successfully.'

    test "@afterAction allows declaration of filters to execute before all actions", ->
      results = []

      class TestController extends Batman.Controller
        routingKey: 'test'
        @afterAction -> results.push 'after!'
        index: ->
          results.push 'action!'
          @render false

      controller = TestController.get('sharedController')
      controller.dispatch 'index'
      equal results[0], 'action!'
      equal results[1], 'after!'

## autoScrollToHash[= true] : boolean

`autoScrollToHash` is a boolean property on the instance level of a controller describing whether or not the controller should automatically scroll the browser window to the element with ID equal to the `hash` parameter. This behaviour emulates the native behaviour of the same nature, but is implemented in Batman so the functionality works after each dispatch (instead of each page refresh) and when Batman is using hash bang routing. `autoScrollToHash` is true by default.

## defaultRenderYield[= 'main'] : String

`defaultRenderYield` is a `String` representing which yield a controller should automatically render into if no yield is mentioned explicitly. `defaultRenderYield` is `'main'` normally, which means calls to `@render()` or actions which rely on the implicit rendering render their views into the `main` yield (and end up wherever `data-yield="main"` is found in your HTML).

## Controller Actions

## executeAction

## render

## redirect

## scrollToHash