Reorder steps for initialization

Reorder steps for initialization

    q     = require 'q'
    fs    = require 'fs'
    async = require 'async'
    uuid  = require 'uuid-1345'

    microtime = require 'microtime'

    EventEmitter2 = require('eventemitter2').EventEmitter2
    emitter       = new EventEmitter2 wildcard: true

    available   = { }
    initialized = { }
    listeners   = { }

    code_root = process.env.SEARCH_ROOT || 'dist'

    underscore = (value) -> value.replace /\W+/g, '_'
    strip      = (name)  -> name.toLowerCase().replace /\W+/g, ''

    SEARCH_ROOTS  = { }
    WRAPPED       = { }
    _INITIALIZERS = { }
    HYDRATED      = { }

    HYRDATION_LISTENERS = { }

    INITIALIZERS = (cls, method) ->
      _INITIALIZERS[cls] = [ ] unless _INITIALIZERS[cls]?

      _INITIALIZERS[cls].push fn: method, called: false

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'initialize'
          'details'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      details: =>
        name  = @.__proto__.constructor.name
        props = for own key, val of @.__proto__
          if key != 'constructor' &&
             key != 'details'     &&
             key != 'initialize'  && ((
               key[0]            == '_' &&
               @.__proto__[key]? == false
             ) || key[0] != '_')

            if typeof val == 'function'
              value = val.constructor.name
            else if Array.isArray val
              value = for v in val
                if typeof v == 'function'
                  v.constructor.name
                else if typeof v == 'object'
                  v.constructor.name
                else
                  v
              value = value.join ','
            else if typeof val == 'object'
              value = val.constructor.name
            else
              value = val

            "#{key} => #{value}"

        "\n  #{name}\n    #{props.filter((e) -> e?).join '\n    '}"

      @LISTEN: (event, callback) => emitter.on event, callback

      @FIRE: (event, args) => emitter.emit event, args

      @SEARCH_ROOT: (mod, path) =>
        Madul.FIRE '$.Madul.search_root.register', "#{mod}": path

        SEARCH_ROOTS[mod] = path.substring 0, path.lastIndexOf '/'

      listen: (event, callback) ->
        Madul.LISTEN "*.#{@constructor.name}.#{event}", callback

      fire: (event, args) ->
        Madul.FIRE "@.#{@constructor.name}.#{event}", args

      warn: (event, details) ->
        Madul.FIRE "!.#{@constructor.name}.#{event}", details

      _report: (name, method, state, id, args) =>
        Madul.FIRE "@.#{name}.#{method}.#{state}",
          uuid:      id
          args:      args
          timestamp: microtime.now()

      _respond: (proto, method, id, deferred) =>
        (state, data) =>
          process.nextTick =>
            deferred[state] data

            proto._report proto.constructor.name, method, state, id, data

      _prep_invocation: (proto, method, input, def) =>
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def

        if Array.isArray input
          input.push (out) => res 'resolve', out
          input.push (err) => res 'reject',  err
          input.push (out) => res 'notify',  out
        else if typeof input == 'object'
          input.done   = (out) => res 'resolve', out
          input.fail   = (err) => res 'reject',  err
          input.update = (out) => res 'notify',  out

          input = [ input ]
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"
          @warn 'input.invalid', msg
          throw new Error msg

        proto._report proto.constructor.name, method, 'invoke', id, input

        input

      _do_wrap: (proto, method) =>
        if method != 'fire' && method != 'warn' && method != 'listen'
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

          if typeof proto[method] == 'function'
            proto["_#{method}"] = proto[method]

            proto[method] = =>
              def  = q.defer()
              args = if arguments[0]? then Array.prototype.slice.call arguments else [ ]

              proto["_#{method}"].apply @, proto._prep_invocation proto, method, args, def

              def.promise
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = for val in proto[method].validate
                @_parse_handle(val).ref

              proto[method].validate = decs
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = for own key, val of proto[method].validate
                { ref } = @_parse_handle val
                proto[method].validate[key] = ref
                ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ @_parse_handle(proto[method].validate).ref ]
            else if typeof proto[method].validate != 'undefined'
              @warn 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            decs = decs.concat(proto[method].before.map (b, i) =>
              { ref } = @_parse_handle b
              proto[method].before[i] = ref
              ref
            ) if proto[method].before?

            decs = decs.concat(proto[method].after.map (a, i) =>
              { ref } = @_parse_handle a
              proto[method].after[i] = ref
              ref
            ) if proto[method].after?

            Madul.FIRE '$.Madul.decorators.hydrate', decs

            @_do_hydrate proto, decs, =>
              proto["_#{method}"] = proto[method]

              proto[method] = =>
                def = q.defer()
                me  = proto["_#{method}"]

                if args_format == 'ARRAY'
                  args = Array.prototype.slice.call arguments

                  if me.validate?
                    validators = for val, i in me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[i]
                      proto[ref].EXECUTE args[i]
                else if args_format == 'OBJECT'
                  args = arguments[0]

                  if me.validate?
                    validators = for own key, val of me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[key]
                      proto[ref].EXECUTE args[key]
                else
                  @warn 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                me.before = [ ] unless me.before?
                me.after  = [ ] unless me.after?

                q.all validators
                .then =>
                  q.all me.before.map (b) =>
                    Madul.FIRE '$.Madul.before_filter.execute', "#{b}": args
                    proto[b].before args
                .then =>
                  me.behavior.apply @, @_prep_invocation proto, method, args, def
                .then (result) =>
                  if me.after.length > 0
                    q.all me.after.map (b) =>
                      Madul.FIRE '$.Madul.after_filter.execute', "#{b}": result
                      b.after result
                  else
                    d = q.defer()

                    process.nextTick => d.resolve result

                    d.promise
                .then  (out) => def.resolve out
                .catch (err) => def.reject  err

                def.promise
          else
            @warn 'cannot-wrap', method

          WRAPPED[proto.constructor.name].push method

      _wrap_methods: (proto, callback) =>
        name    = proto.constructor.name
        to_wrap = [ ]

        while proto? && Object.keys(proto).length > 0 && WRAPPED[name]? == false
          to_wrap.push { proto, name, methods: [ ] }

          for own prop, body of proto
            if prop[0]                  != '_'         &&
               typeof proto["_#{prop}"] == 'undefined' &&
               WRAP(name, prop)         == true

              continue if proto.deps? && proto.deps.indexOf(prop.replace(/_/g, '-')) > -1

              if typeof body == 'function' || typeof body?.behavior == 'function'
                to_wrap[to_wrap.length - 1].methods.push prop

          proto = proto.__proto__
          name  = proto.constructor.name

        async.each to_wrap.reverse(), (wrap, completed) =>
          async.each wrap.methods, (method, next) =>
            wrap.proto._do_wrap wrap.proto, method

            INITIALIZERS wrap.name, method if method[0] == '$'

            next()
          , => @_call_initializers_for wrap.proto, wrap.name, completed
        , callback

      _make_available: (name, mod) =>
        Madul.FIRE "$.#{name}.available"

        available[strip name] = mod

      _hydrate_deps: (proto, done) =>
        protos = [ proto ]

        if proto.__proto__?
          while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            protos.push proto = proto.__proto__

        async.each protos.reverse(), (p, next) =>
          name = p.constructor.name

          if p.hasOwnProperty 'deps'
            if HYDRATED[name] == undefined
              HYDRATED[name]            = false
              HYRDATION_LISTENERS[name] = [ next ]

              p._do_hydrate p, p.deps, =>
                HYDRATED[name] = true

                for listener in HYRDATION_LISTENERS[name]
                  listener()
            else if HYDRATED[name] == false
              HYRDATION_LISTENERS[name].push next
            else if HYDRATED[name] == true
              next()
          else
            next()
        , done

      _init_if_madul: (path, callback) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.name == 'Madul'
          if is_madul                            == false      &&
             proto.constructor.name              != 'Object'   &&
             typeof proto                        == 'function' &&
             typeof proto.__super__?.constructor == 'function'
            proto = proto.__super__.constructor
          else
            proto = undefined

        if is_madul
          new mod()
            .initialize()
            .then callback
        else
          callback mod

      _load: (me, name, path, loaded) =>
        me._init_if_madul path, (mod) =>
          me._make_available name, mod
          loaded mod

      _check: (me, path, dep, ref, finished) =>
        fs.readdir path, (err, files) =>
          if err?
            me.warn 'file-not-found', err

            done type: 'ERROR', info: err
          else
            async.each files, (f, next) =>
              depth = "#{path}/#{f}"

              fs.stat depth, (e, s) =>
                if s.isDirectory() && f[0] != '.'
                  me._check me, depth, dep, ref, next
                else if s.isFile() && f.substring(0, f.length - 3) == dep
                  me._load me, ref, depth, (mod) => me._do_add me, mod, ref, next
                else
                  next()
            , finished

      _do_add: (me, mod, ref, next) =>
        Madul.FIRE "$.#{me.constructor.name}.dependency.register", ref

        me[underscore ref] = mod

        next()

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, mod, ref, next

      _parse_handle: (value) =>
        tokens = value.split '='

        if tokens.length == 2
          initer = tokens[1].trim()
          t      = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

          toks = initer.split ':'

          if toks.length == 2
            initer = toks[0].trim()
            pres   = toks[1].split(',').map (p) => p.trim()
          else if toks.length == 1
            initer = toks[0].trim()
          else
            return next @warn 'dependency-initializer.invalid', tokens[1]

        else if tokens.length == 1
          t = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

        else
          return next @warn 'dependency.invalid', d

        { ref: alias || name, alias, name, root, initer, pres }

      _do_hydrate: (proto, deps, hydration_complete) =>
        initers = [ ]

        async.each deps, (d, next) =>
          { ref, alias, name, root, initer, pres } = @_parse_handle d

          if pres?
            insert_at = for p in pres
              index_for = (sibling) => sibling.alias == p.alias

              initers.find index_for

            insert_at.sort()

            insert_at = if insert_at.length == 0 then 0 else insert_at[insert_at.length - 1]

            initers.splice insert_at, 0, alias: alias, execute: initer

          if proto[underscore ref]? == false
            if available[strip ref]? == true
              proto._do_add proto, available[strip ref], ref, next
            else
              try
                proto._add proto, ref, name, next
              catch e
                if root?
                  Madul.FIRE '$.Madul.search_root.load', { name, alias, root }

                  proto._check proto, root, name, ref, next
                else
                  cwd = process.cwd()
                  pkg = "#{cwd}/node_modules/#{name}/package.json"

                  fs.stat pkg, (err, stat) =>
                    if stat?.isFile()
                      fs.readFile pkg, 'utf8', (err, data) =>
                        json = JSON.parse data
                        main = json.main || json._main || 'index.js'
                        path = "#{cwd}/node_modules/#{name}/#{main}"

                        proto._add proto, ref, path, next
                    else
                      proto._check proto, "#{cwd}/#{code_root}", name, ref, next
          else
            next()
        , =>
          async.eachSeries initers, (initer, next) =>
            proto[initer.execute].apply(@).then next
          , hydration_complete

      _finish_up: (proto, args) =>
        name = proto.constructor.name

        if listeners[name]?
          async.each listeners[name], (listener, next) =>
            listener @
            next()
          , => @_register_initialized name
        else
          @_register_initialized name

      _register_initialized: (name) =>
        @_make_available name, @

        initialized[name] = true

        Madul.FIRE "$.#{name}.initialized"

      _call_initializers_for: (proto, name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              proto[initializer.fn].apply @
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      initialize: =>
        deferred = q.defer()
        proto    = @.__proto__
        name     = proto.constructor.name

        Madul.FIRE "$.#{name}.request_instance"

        if initialized[name] == undefined
          Madul.FIRE "$.#{name}.initialize"

          initialized[name] = false
          listeners[name]   = [ deferred.resolve ]

          @_hydrate_deps proto, => @_wrap_methods proto, => @_finish_up proto
        else if initialized[name] == false
          listeners[name].push deferred.resolve
        else if initialized[name] == true
          process.nextTick => deferred.resolve available[strip name]

        deferred.promise

    module.exports = Madul

    q     = require 'q'
    fs    = require 'fs'
    async = require 'async'
    uuid  = require 'uuid-1345'

    microtime = require 'microtime'

    EventEmitter2 = require('eventemitter2').EventEmitter2
    emitter       = new EventEmitter2 wildcard: true

    available   = { }
    initialized = { }
    listeners   = { }

    code_root = process.env.SEARCH_ROOT || 'dist'

    underscore = (value) -> value.replace /\W+/g, '_'
    strip      = (name)  -> name.toLowerCase().replace /\W+/g, ''

    SEARCH_ROOTS  = { }
    WRAPPED       = { }
    _INITIALIZERS = { }
    HYDRATED      = { }

    HYRDATION_LISTENERS = { }

    INITIALIZERS = (cls, method) ->
      _INITIALIZERS[cls] = [ ] unless _INITIALIZERS[cls]?

      _INITIALIZERS[cls].push fn: method, called: false

    WRAP = (cls, method) ->
      unless WRAPPED[cls]?
        WRAPPED[cls] = [
          'constructor'
          'initialize'
          'details'
        ]

      WRAPPED[cls].indexOf(method) < 0

    class Madul

      details: =>
        name  = @.__proto__.constructor.name
        props = for own key, val of @.__proto__
          if key != 'constructor' &&
             key != 'details'     &&
             key != 'initialize'  && ((
               key[0]            == '_' &&
               @.__proto__[key]? == false
             ) || key[0] != '_')

            if typeof val == 'function'
              value = val.constructor.name
            else if Array.isArray val
              value = for v in val
                if typeof v == 'function'
                  v.constructor.name
                else if typeof v == 'object'
                  v.constructor.name
                else
                  v
              value = value.join ','
            else if typeof val == 'object'
              value = val.constructor.name
            else
              value = val

            "#{key} => #{value}"

        "\n  #{name}\n    #{props.filter((e) -> e?).join '\n    '}"

      @LISTEN: (event, callback) => emitter.on event, callback

      @FIRE: (event, args) => emitter.emit event, args

      @SEARCH_ROOT: (mod, path) =>
        Madul.FIRE '$.Madul.search_root.register', "#{mod}": path

        SEARCH_ROOTS[mod] = path.substring 0, path.lastIndexOf '/'

      listen: (event, callback) ->
        Madul.LISTEN "*.#{@constructor.name}.#{event}", callback

      fire: (event, args) ->
        Madul.FIRE "@.#{@constructor.name}.#{event}", args

      warn: (event, details) ->
        Madul.FIRE "!.#{@constructor.name}.#{event}", details

      _report: (name, method, state, id, args) =>
        Madul.FIRE "@.#{name}.#{method}.#{state}",
          uuid:      id
          args:      args
          timestamp: microtime.now()

      _respond: (proto, method, id, deferred) =>
        (state, data) =>
          process.nextTick =>
            deferred[state] data

            proto._report proto.constructor.name, method, state, id, data

      _prep_invocation: (proto, method, input, def) =>
        id  = uuid.v4fast()
        res = proto._respond proto, method, id, def

        if Array.isArray input
          input.push (out) => res 'resolve', out
          input.push (err) => res 'reject',  err
          input.push (out) => res 'notify',  out
        else if typeof input == 'object'
          input.done   = (out) => res 'resolve', out
          input.fail   = (err) => res 'reject',  err
          input.update = (out) => res 'notify',  out

          input = [ input ]
        else
          msg = "input to #{proto.constructor.name}.#{method} must be an Array of Object"
          @warn 'input.invalid', msg
          throw new Error msg

        proto._report proto.constructor.name, method, 'invoke', id, input

        input

      _do_wrap: (proto, method) =>
        if method != 'fire' && method != 'warn' && method != 'listen'
          Madul.FIRE "$.#{proto.constructor.name}.#{method}.wrap"

          if typeof proto[method] == 'function'
            proto["_#{method}"] = proto[method]

            proto[method] = =>
              def  = q.defer()
              args = if arguments[0]? then Array.prototype.slice.call arguments else [ ]

              proto["_#{method}"].apply @, proto._prep_invocation proto, method, args, def

              def.promise
          else if typeof proto[method] == 'object'

            if Array.isArray proto[method].validate
              args_format = 'ARRAY'
              decs        = for val in proto[method].validate
                @_parse_handle(val).ref

              proto[method].validate = decs
            else if typeof proto[method].validate == 'object'
              args_format = 'OBJECT'
              decs        = for own key, val of proto[method].validate
                { ref } = @_parse_handle val
                proto[method].validate[key] = ref
                ref
            else if typeof proto[method].validate == 'string'
              args_format = 'ARRAY'
              decs        = [ @_parse_handle(proto[method].validate).ref ]
            else if typeof proto[method].validate != 'undefined'
              @warn 'meta.invalid', validate: 'must be a String, Object, or Array'
              return
            else
              args_format = 'ARRAY'
              decs        = [ ]

            decs = decs.concat(proto[method].before.map (b, i) =>
              { ref } = @_parse_handle b
              proto[method].before[i] = ref
              ref
            ) if proto[method].before?

            decs = decs.concat(proto[method].after.map (a, i) =>
              { ref } = @_parse_handle a
              proto[method].after[i] = ref
              ref
            ) if proto[method].after?

            Madul.FIRE '$.Madul.decorators.hydrate', decs

            @_do_hydrate proto, decs, =>
              proto["_#{method}"] = proto[method]

              proto[method] = =>
                def = q.defer()
                me  = proto["_#{method}"]

                if args_format == 'ARRAY'
                  args = Array.prototype.slice.call arguments

                  if me.validate?
                    validators = for val, i in me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[i]
                      proto[ref].EXECUTE args[i]
                else if args_format == 'OBJECT'
                  args = arguments[0]

                  if me.validate?
                    validators = for own key, val of me.validate
                      { ref } = @_parse_handle val
                      Madul.FIRE '$.Madul.validator.execute', "#{ref}": args[key]
                      proto[ref].EXECUTE args[key]
                else
                  @warn 'cannot-continue', 'No arg format specified'

                  return def.reject 'No arg format specified'

                me.before = [ ] unless me.before?
                me.after  = [ ] unless me.after?

                q.all validators
                .then =>
                  q.all me.before.map (b) =>
                    Madul.FIRE '$.Madul.before_filter.execute', "#{b}": args
                    proto[b].before args
                .then =>
                  me.behavior.apply @, @_prep_invocation proto, method, args, def
                .then (result) =>
                  if me.after.length > 0
                    q.all me.after.map (b) =>
                      Madul.FIRE '$.Madul.after_filter.execute', "#{b}": result
                      b.after result
                  else
                    d = q.defer()

                    process.nextTick => d.resolve result

                    d.promise
                .then  (out) => def.resolve out
                .catch (err) => def.reject  err

                def.promise
          else
            @warn 'cannot-wrap', method

          WRAPPED[proto.constructor.name].push method

      _wrap_methods: (proto, callback) =>
        name    = proto.constructor.name
        to_wrap = [ ]

        while proto? && Object.keys(proto).length > 0 && WRAPPED[name]? == false
          to_wrap.push { proto, name, methods: [ ] }

          for own prop, body of proto
            if prop[0]                  != '_'         &&
               typeof proto["_#{prop}"] == 'undefined' &&
               WRAP(name, prop)         == true

              continue if proto.deps? && proto.deps.indexOf(prop.replace(/_/g, '-')) > -1

              if typeof body == 'function' || typeof body?.behavior == 'function'
                to_wrap[to_wrap.length - 1].methods.push prop

          proto = proto.__proto__
          name  = proto.constructor.name

        async.each to_wrap.reverse(), (wrap, completed) =>
          async.each wrap.methods, (method, next) =>
            wrap.proto._do_wrap wrap.proto, method

            INITIALIZERS wrap.name, method if method[0] == '$'

            next()
          , => @_call_initializers_for wrap.proto, wrap.name, completed
        , callback

      _make_available: (name, mod) =>
        Madul.FIRE "$.#{name}.available"

        available[strip name] = mod

      _hydrate_deps: (proto, done) =>
        protos = [ proto ]

        if proto.__proto__?
          while proto.__proto__? && Object.keys(proto.__proto__).length > 0
            protos.push proto = proto.__proto__

        async.each protos.reverse(), (p, next) =>
          name = p.constructor.name

          if p.hasOwnProperty 'deps'
            if HYDRATED[name] == undefined
              HYDRATED[name]            = false
              HYRDATION_LISTENERS[name] = [ next ]

              p._do_hydrate p, p.deps, =>
                HYDRATED[name] = true

                for listener in HYRDATION_LISTENERS[name]
                  listener()
            else if HYDRATED[name] == false
              HYRDATION_LISTENERS[name].push next
            else if HYDRATED[name] == true
              next()
          else
            next()
        , done

      _init_if_madul: (path, callback) =>
        mod      = require path
        proto    = mod
        is_madul = false

        while proto
          is_madul = true if proto.name == 'Madul'
          if is_madul                            == false      &&
             proto.constructor.name              != 'Object'   &&
             typeof proto                        == 'function' &&
             typeof proto.__super__?.constructor == 'function'
            proto = proto.__super__.constructor
          else
            proto = undefined

        if is_madul
          new mod()
            .initialize()
            .then callback
        else
          callback mod

      _load: (me, name, path, loaded) =>
        me._init_if_madul path, (mod) =>
          me._make_available name, mod
          loaded mod

      _check: (me, path, dep, ref, finished) =>
        fs.readdir path, (err, files) =>
          if err?
            me.warn 'file-not-found', err

            done type: 'ERROR', info: err
          else
            async.each files, (f, next) =>
              depth = "#{path}/#{f}"

              fs.stat depth, (e, s) =>
                if s.isDirectory() && f[0] != '.'
                  me._check me, depth, dep, ref, next
                else if s.isFile() && f.substring(0, f.length - 3) == dep
                  me._load me, ref, depth, (mod) => me._do_add me, mod, ref, next
                else
                  next()
            , finished

      _do_add: (me, mod, ref, next) =>
        Madul.FIRE "$.#{me.constructor.name}.dependency.register", ref

        me[underscore ref] = mod

        next()

      _add: (me, ref, path, next) =>
        me._init_if_madul path, (mod) =>
          me._make_available ref, mod
          me._do_add me, mod, ref, next

      _parse_handle: (value) =>
        tokens = value.split '='

        if tokens.length == 2
          initer = tokens[1].trim()
          t      = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

          toks = initer.split ':'

          if toks.length == 2
            initer = toks[0].trim()
            pres   = toks[1].split(',').map (p) => p.trim()
          else if toks.length == 1
            initer = toks[0].trim()
          else
            return next @warn 'dependency-initializer.invalid', tokens[1]

        else if tokens.length == 1
          t = tokens[0].split '->'

          if t[0].indexOf('#') > -1
            r = t[0].split '#'

            root = SEARCH_ROOTS[r[0].trim()]
            t[0] = r[1]

          if t.length == 2
            name  = t[0].trim()
            alias = t[1].trim()
          else if t.length == 1
            name = alias = t[0].trim()
          else
            return next @warn 'alias.invalid', tokens[1]

        else
          return next @warn 'dependency.invalid', d

        { ref: alias || name, alias, name, root, initer, pres }

      _do_hydrate: (proto, deps, hydration_complete) =>
        initers = [ ]

        async.each deps, (d, next) =>
          { ref, alias, name, root, initer, pres } = @_parse_handle d

          if pres?
            insert_at = for p in pres
              index_for = (sibling) => sibling.alias == p.alias

              initers.find index_for

            insert_at.sort()

            insert_at = if insert_at.length == 0 then 0 else insert_at[insert_at.length - 1]

            initers.splice insert_at, 0, alias: alias, execute: initer

          if proto[underscore ref]? == false
            if available[strip ref]? == true
              proto._do_add proto, available[strip ref], ref, next
            else
              try
                proto._add proto, ref, name, next
              catch e
                if root?
                  Madul.FIRE '$.Madul.search_root.load', { name, alias, root }

                  proto._check proto, root, name, ref, next
                else
                  cwd = process.cwd()
                  pkg = "#{cwd}/node_modules/#{name}/package.json"

                  fs.stat pkg, (err, stat) =>
                    if stat?.isFile()
                      fs.readFile pkg, 'utf8', (err, data) =>
                        json = JSON.parse data
                        main = json.main || json._main || 'index.js'
                        path = "#{cwd}/node_modules/#{name}/#{main}"

                        proto._add proto, ref, path, next
                    else
                      proto._check proto, "#{cwd}/#{code_root}", name, ref, next
          else
            next()
        , =>
          async.eachSeries initers, (initer, next) =>
            proto[initer.execute].apply(@).then next
          , hydration_complete

      _finish_up: (proto, args) =>
        name = proto.constructor.name

        if listeners[name]?
          async.each listeners[name], (listener, next) =>
            listener @
            next()
          , => @_register_initialized name
        else
          @_register_initialized name

      _register_initialized: (name) =>
        @_make_available name, @

        initialized[name] = true

        Madul.FIRE "$.#{name}.initialized"

      _call_initializers_for: (proto, name, callback) =>
        if _INITIALIZERS[name]?
          async.each _INITIALIZERS[name], (initializer, next) =>
            if initializer.called == false
              proto[initializer.fn].apply @
                .then =>
                  initializer.called = true
                  next()
            else
              next()
          , callback
        else
          callback()

      initialize: =>
        deferred = q.defer()
        proto    = @.__proto__
        name     = proto.constructor.name

        Madul.FIRE "$.#{name}.request_instance"

        if initialized[name] == undefined
          Madul.FIRE "$.#{name}.initialize"

          initialized[name] = false
          listeners[name]   = [ deferred.resolve ]

          @_wrap_methods()
          @_hydrate_deps => @_invoke_parent_initializers => @_finish_up proto
        else if initialized[name] == false
          listeners[name].push deferred.resolve
        else if initialized[name] == true
          process.nextTick => deferred.resolve available[strip name]

        deferred.promise

    module.exports = Madul


Wording

Wording

    EventEmitter      = require('events').EventEmitter
    _                 = require 'underscore'
    log               = require 'simplog'
    AwesomeWebSocket  = require('awesome-websocket').AwesomeWebSocket

EpiClient
=========
This is the base client for communicating with epiquery2.

    class EpiClient extends EventEmitter

The @url constructor argument can be either a singular string or an array of strings that represent the
epiquery2 endpoint(s).

      constructor: (@url) ->
        @connect()

Under the hood, we're using the [AwesomeWebSocket](https://github.com/glg/awesome-websocket) to ensure auto-reconnect
on interruptions and endpoint hunting to find the fastest connection.

      connect: =>
        @ws = new AwesomeWebSocket(@url)
        @queryId = 0
        @ws.onmessage = @onMessage
        @ws.onclose = @onClose
        @ws.onopen = () ->
          log.debug "Epiclient connection opened"
        @ws.onerror = (err) ->
          log.error "EpiClient socket error: ", err

The **query** function kicks off the processing of a query which triggers a handful of events in the lifecycle of a query.  See the events section below for more details.

**connectionName** - The string key that maps to an epiquery2 named connection e.g. 'mysql', 'mssql', 'file'.  See more [here](https://github.com/igroff/epiquery2#configuration).

**template** - The path to the template you're querying.  The path is relative to the root of the template directory defined in epiquery2.

**data** - This is a just javascript object you can pass that contains any data you want to use in your epiquery template.

**queryId** - A unique identifier used to refer to the query throughout it's Active period. It will be included with all messages generated during it's processing. It is the caller's responsibility to generate a unique id for each query requested.

      query: (connectionName, template, data, queryId=null) =>
        req =
          templateName: template
          connectionName: connectionName
          data: data
        req.queryId = null || queryId
        req.closeOnEnd = data.closeOnEnd if data
        # if someone has asked us to close on end, we want our fancy
        # underlying reconnectint sockets to not reconnect
        @ws.forceClose = req.closeOnEnd

        log.debug "executing query: #{template} data:#{JSON.stringify(data)}"
        @ws.send JSON.stringify(req)

Echoes events returned from epiquery.

      onMessage: (message) =>
        # if the browser has wrapped this for use, we'll be interested in its
        # 'data' element
        message = message.data if message.type? and message.type = 'message'
        message = JSON.parse(message) if typeof message is 'string'
        handler = @['on' + message.message]
        if handler
          handler(message)

      onClose: () =>
        @emit 'close'

## Events
They're all pretty self explanatory.  The messages provided to the events have the optional field **queryId** that corresponds to the  queryId that was provided to the **query** function.  Use that to track a particular request in the query's lifecycle.

Invoked at the start of the query's lifecycle.  No query has occurred yet.

      onbeginquery: (msg) => @emit 'beginquery', msg

Invoked when a new row set is began.  Row sets are the result of executing an individual statement.  For example, if you executed two SQL statements, each would be its own row set.

      onbeginrowset: (msg) => @emit 'beginrowset', msg

Invoked every time a row of data is returned from a row set.

      onrow: (msg) => @emit 'row', msg

Invoked at the end of a row set.

      onendrowset: (msg) => @emit 'endrowset', msg

Invoked at the end of the query's overall lifecycle.

      onendquery: (msg) => @emit 'endquery', msg

Invoked if an error is encountered while processing the query.

      onerror: (msg) => @emit 'error', msg

    module.exports = EpiClient

    EventEmitter      = require('events').EventEmitter
    _                 = require 'underscore'
    log               = require 'simplog'
    AwesomeWebSocket  = require('awesome-websocket').AwesomeWebSocket

EpiClient
=========
This is the base client for communicating with epiquery2.

    class EpiClient extends EventEmitter

The @url constructor argument can be either a singular string or an array of strings that represent the
epiquery2 endpoint(s).

      constructor: (@url) ->
        @connect()

Under the hood, we're using the [AwesomeWebSocket](https://github.com/glg/awesome-websocket) to ensure auto-reconnect
on interruptions and endpoint hunting to find the fastest connection.

      connect: =>
        @ws = new AwesomeWebSocket(@url)
        @queryId = 0
        @ws.onmessage = @onMessage
        @ws.onclose = @onClose
        @ws.onopen = () ->
          log.debug "Epiclient connection opened"
        @ws.onerror = (err) ->
          log.error "EpiClient socket error: ", err

The **query** function kicks off the processing of a query which triggers a handful of events in the lifecycle of a query.  See the events section below for more details.

**connectionName** - The string key that maps to an epiquery2 named connection e.g. 'mysql', 'mssql', 'file'.  See more [here](https://github.com/igroff/epiquery2#configuration).

**template** - The path to the template you're querying.  The path is relative to the root of the template directory defined in epiquery2.

**data** - This is a just javascript object you can pass that contains any data you want to use in your epiquery template.

**queryId** - A unique identifier used to refer to the query throughout it's Active period. It will be included with all messages generated during it's processing. It is the caller's responsibility to generate a unique id for each query requested.

      query: (connectionName, template, data, queryId=null) =>
        req =
          templateName: template
          connectionName: connectionName
          data: data
        req.queryId = null || queryId
        req.closeOnEnd = data.closeOnEnd if data
        # if someone has asked us to close on end, we want our fancy
        # underlying reconnectint sockets to not reconnect
        @ws.forceClose = req.closeOnEnd

        log.debug "executing query: #{template} data:#{JSON.stringify(data)}"
        @ws.send JSON.stringify(req)

Echoes events returned from epiquery.

      onMessage: (message) =>
        # if the browser has wrapped this for use, we'll be interested in its
        # 'data' element
        message = message.data if message.type? and message.type = 'message'
        message = JSON.parse(message) if typeof message is 'string'
        handler = @['on' + message.message]
        if handler
          handler(message)

      onClose: () =>
        @emit 'close'

## Events
They're all pretty self explanatory.  The messages provided to the events have the optional field **queryId** that corresponds to the  queryId that was provided to the **query** function.  Use that to track a particular request in the query's lifecycle.

Invoked at the start of the query's lifecycle.  No query has occurred yet.

      onbeginquery: (msg) => @emit 'beginquery', msg

Invoked when a new row set is began.  Row sets are the result of executing a singular query.  For example, if you executed two SQL statements, each would be its own row set.

      onbeginrowset: (msg) => @emit 'beginrowset', msg

Invoked every time a row of data is returned from a row set.

      onrow: (msg) => @emit 'row', msg

Invoked at the end of a row set.

      onendrowset: (msg) => @emit 'endrowset', msg

Invoked at the end of the query's overall lifecycle.

      onendquery: (msg) => @emit 'endquery', msg

Invoked if an error is encountered while processing the query.

      onerror: (msg) => @emit 'error', msg

    module.exports = EpiClient


properties base

properties base

Copyright 2014 - 2015
Author: Varuna Jayasiri http://blog.varunajayasiri.com

#Properties Base

    Mod.require 'Models.Util',
     (UTIL) ->

Class

      class Base
       propertyType: 'base'
       _defaults: {}

       @extend: ->
        @::_defaults = UTIL.extend {}, @::_defaults

       @default: (name, value) ->
        @::_defaults[name] = value

       @isValidSchema: (schema) ->
        for k of schema
         if not @::_defaults[k]?
          return false

        return true

       @default 'required', false
       @default 'default', -> null
       @default 'isDefault', (value) ->
        return true if not value?
        return false

       constructor: (schema, name) ->
        @_name = name
        @schema = {}

        for k, v of @_defaults
         if schema[k]?
          @schema[k] = schema[k]
         else
          @schema[k] = v

Abstract methods

       toJSON: (value, stack) ->
        throw new Error "#{@propertyType}: toJSON not implementaed"

       toJSONFULL: (value, stack) ->
        throw new Error "#{@propertyType}: toJSONFULL not implementaed"

       edit: (elem, value, onChanged, stack) ->
        throw new Error "#{@propertyType}: edit not implementaed"

Error helper

       error: (error) ->
        return {
         score: 0
         value: @schema.default.call this
         errors: [error]
        }

       parse: (data, stack) ->
        if not data?
         if @schema.required
          return (@error 'required')
         else
          return {score: 1, value: (@schema.default.call this), errors: []}

        return true

       isDefault: (value, stack) ->
        @schema.isDefault.call this, value, stack

      Mod.set 'Models.Property.Base', Base

Copyright 2014 - 2015
Author: Varuna Jayasiri http://blog.varunajayasiri.com

#List

    Mod.require 'Models.Util',
     (UTIL) ->

Class

      class Base
       propertyType: 'base'
       _defaults: {}

       @extend: ->
        @::_defaults = UTIL.extend {}, @::_defaults

       @default: (name, value) ->
        @::_defaults[name] = value

       @isValidSchema: (schema) ->
        for k of schema
         if not @::_defaults[k]?
          return false

        return true

       constructor: (schema, name) ->
        @_name = name
        @schema = {}

        for k, v of @_defaults
         if schema[k]?
          @schema[k] = schema[k]
         else
          @schema[k] = v

       error: (error) ->
        return {
         score: 0
         value: @schema.default.call this
         errors: [error]
        }

       parse: (data) ->
        if not data?
         if @schema.required
          return (@error 'required')
         else
          return {score: 1, value: (@schema.default.call this), errors: []}

        return true

       @default 'required', false
       @default 'default', -> null
       @default 'isDefault', (value) ->
        return true if not value?
        return false

       isDefault: (value) ->
        @schema.isDefault.call this, value

      Mod.set 'Models.Property.Base', Base


[Sheet] Forgot to increment start_index by frame

Jelli Game Engine

#  Sheet  #

`Sheet()` generates sprite-sheets and manages their rendering on a `CanvasRenderingContext2D`.
It is packaged with `Sprite()`, which describes a single sprite on the sheet.

##  General functions  ##

The function `drawSprite()` is called by `Sprite`s and `Sheet`s in order to draw their images.
It is not exposed to the window.

    drawSprite = (sheet, start_index, context, x, y, frame = 1) ->

…That's a lot of arguments. Let's go through them:

- `sheet` is the `Sheet` from which to draw the sprite
- `start_index` gives us the index of the sprite within the sheet
- `context` is the `CanvasRenderingContext2D` on which to draw the sprite
- `x` is the x-coordinate of the top-left corner of the sprite
- `y` is the y-coordinate of the top-left corner of the sprite
- `frame` is merely there as a convenience: It increments `start_index` by its value

The first thing we do is make sure everything is typed correctly.
The `sheet` and `context`, clearly, need to be of a certain type in order for this to work.
If any of the other provided arguments aren't numbers, however, we can go ahead and reset them to zero.

        unless sheet instanceof Sheet and start_index < sheet.size and context instanceof CanvasRenderingContext2D then return
        if isNaN(start_index = Number(start_index)) then start_index = 0
        if isNaN(x = Number(x)) then x = 0
        if isNaN(y = Number(y)) then y = 0
        if isNaN(frame = Number(frame)) then frame = 0

Now we can increment `start_index` by `frame`'s value:

        `start_index` += frame

Next, we need to find the horizontal (`i`) and vertical (`j`) position of the sprite on the sheet.
We can get this information from `start_index` with a little math:

        i = start_index % sheet.width
        j = Math.floor start_index / sheet.width

These two lines just make the image a little easier to access:

        source = sheet.source
        image = sheet.image

Now we have all we need to draw the sprite!
There is a HUGE `if`-statement that precedes the draw function, because we want to make sure that what we're drawing is actually there.
If it isn't, then obviously we can't draw anything.

        if (source instanceof HTMLImageElement and source.complete or source instanceof SVGImageElement or source instanceof HTMLCanvasElement or createImageBitmap? and (image instanceof ImageBitmap or source instanceof ImageBitmap)) and not isNaN(i) and not isNaN(j) and Number(width = sheet.sprite_width) and Number(height = sheet.sprite_height) then context.drawImage (if createImageBitmap? and image instanceof ImageBitmap then image else source), i * width, j * height, width, height, x, y, width, height

Let's go through what those did.
First, we make sure that the `Sheet` actually has an image associated with it:

-   `source instanceof HTMLImageElement and source.complete`—
    If the image source is an `<img>` element, then it needs to have finished loading.

-   `source instanceof SVGImageElement or source instanceof HTMLCanvasElement`—
    The source doesn't have to be an `<img>` element though! It can also be an `<svg>` or a `<canvas>`.

-   `createImageBitmap? and (image instanceof ImageBitmap or source instanceof ImageBitmap)`—
    Finally, the source can be an `ImageBitmap`.
    This isn't supported in all browsers, so we check to make sure `createImageBitmap` exists first.
    However, if `createImageBitmap` *is* supported, then `Sheet`s have a special property, `Sheet.image`, which might contain one, and this should be given preference.

We also need to make sure that the sprite exists on the sheet:

-   `not isNaN(i) and not isNaN(j)`—
    This makes sure that our indices are actually, y'know, numbers.

-   `Number(width = sheet.sprite_width) and Number(height = sheet.sprite_height)`—
    This makes sure that the `Sheet` has a non-zero width and height.
    It also sets the variables `width` and `height` to those values, for convenient access later.

Finally, we can draw the sprite.
Again, we preference `image` if it is defined.

##  Sprite  ##

The `Sprite` constructor creates a reference to a sprite on a sheet.
For efficiency's sake, it does *not* actually contain any of the image data associated with that sprite.
The constructor takes three arguments: `sheet`, which gives the sheet; `index`, which is the index of the sprite on the sheet; and `length`, which for animated sprites gives the length of the animation.

    Sprite = (sheet, index, length = 1) ->

If `index` or `length` aren't numbers, then we go ahead and set them to `0` and `1`, respectively.

        if isNaN(index = Number(index)) then index = 0
        if isNaN(length = Number(length)) then length = 0

Now we can set the properties.
Note that `draw` simply binds `drawSprite` to the given `Sheet` and `index`.

        @draw = drawSprite.bind(null, sheet, index)
        @height = if sheet instanceof Sheet then sheet.sprite_height else 0
        @index = index
        @frames = length
        @sheet = if sheet instanceof Sheet then sheet else null
        @width = if sheet instanceof Sheet then sheet.sprite_width else 0

Since `Sprite`s are just static references, they should be immutable:

        Object.freeze this

And we're done!

`Sprite`s are very simple, and because the `draw` function is bound above, they don't have a prototype.
For purposes of inheritance, however, I've thrown this minimal one together:

    Sprite.prototype = {draw: ->}
    Object.freeze Sprite.prototype

##  Sheet  ##

`Sheet`s associate images with data and methods to make them easily referencable as sprite-sheets.

###  The constructor  ###

The `Sheet` constructor only takes three arguments: `source`, which gives the source image for the sheet, `sprite_width`, which gives the width of the sprites, and `sprite_height`, which gives their height.
In doing so, it makes the assumption that sprites and sprite-sheets do not have any borders or padding.
(Because borders and padding result in larger download times for users, this restriction is considered acceptable, but it may be lifted at some time in the future.)

    Sheet = (source, sprite_width, sprite_height) ->

First, we need to handle the arguments.
If `source` isn't an image type that we recognize, we go ahead and set it to `null`.
And if the `sprite_width` or `sprite_height` aren't recognizable as numbers, we set them to 0.
(Note from the above that a `Sheet` with zero `sprite_width` or `sprite_height` cannot be drawn.)

        unless source instanceof HTMLImageElement or source instanceof SVGImageElement or source instanceof HTMLCanvasElement or createImageBitmap? and source instanceof ImageBitmap then source = null
        if isNaN(sprite_width = Number(sprite_width)) then sprite_width = 0
        if isNaN(sprite_height = Number(sprite_height)) then sprite_height = 0

Recall that we need to check for `createImageBitmap` before checking to see if the source is an `ImageBitmap`.

We can get the width and height of the image from one of two sources, depending on the source type.
All of the accepted types have `width` and `height` properties, which specify their dimensions.
However, `HTMLImageElement`s also have `naturalWidth` and `naturalHeight` properties, and these should be preferred for pixel-perfect rendering.

If for some reason we can't get *either* of these properties, then the `source_width` and `source_height` are set to zero.

        unless source? and not isNaN(source_width = Number(if source.naturalWidth? then source.naturalWidth else source.width)) then source_width = 0
        unless source? and not isNaN(source_height = Number(if source.naturalHeight? then source.naturalHeight else source.height)) then source_height = 0

We now have everything we need to define the properties.
Note that `width` and `height` are provided in sprite-units, not pixels.
If `sprite_width` or `sprite_height` are `0`, then the corresponding `width` and `height` are obviously `NaN`.

        @height = Math.floor source_height / sprite_height
        @source = source
        @sprite_height = sprite_height
        @sprite_width = sprite_width
        @width = Math.floor source_width / sprite_width

The `size` property is just `width` times `height`.

        @size = @width * @height

`ImageBitmap`s are optimized for drawing to the canvas.
If they are supported, we can pre-render the sprite-sheet and store this in the `image` property.

        if createImageBitmap? then (createImageBitmap source).then (image) => @image = image

Because `Sheet`s contain static images, it doesn't make sense for them to change after creation.
We freeze them:

        Object.freeze this

For convenience's sake, two static method has been defined for `Sheet` to let you draw arbitrary sprites.
These are largely intended for use with callbacks.

The first is called `draw`, and takes five arguments:

- `context`: A `CanvasRenderingContext2D`
- `sprite`: A `Sprite`
- `x`: The x-coordinate at which to draw the sprite
- `y`: The y-coordinate at which to draw the sprite
- `frame`: The frame of the animation which to draw

It maps onto `sprite.draw`:

    Sheet.draw = (context, sprite, x, y, frame = 0) -> if sprite instanceof Sprite then sprite.draw context, x, y, frame

The second is called `drawSheetAtIndex`, and also takes five arguments:

- `context`: A `CanvasRenderingContext2D`
- `sheet`: A `Sheet`
- `index`: The index of the sprite
- `x`: The x-coordinate at which to draw the sprite
- `y`: The y-coordinate at which to draw the sprite

It maps onto `sheet.drawIndex`:

    Sheet.drawSheetAtIndex = (context, sheet, index, x, y) -> if sheet instanceof Sheet then sheet.drawIndex context, index, x, y

Finally, the `Sprite` constructor is added to `Sheet` for later access:

    Sheet.Sprite = Sprite

And now we can make `Sheet` available to the window:

    window.Sheet = Sheet

##  The prototype  ##

The `Sheet` prototype is fairly minimal, consisting of only two functions.

    Sheet.prototype = {

The first, `drawIndex`, draws the sprite located at the given `index`.
It is little more than a repackaging of `drawSprite`.

        drawIndex: (context, index, x, y) -> drawSprite this, index, context, x, y

The second, `getSprite`, creates a new `Sprite` pointing to the given `index`.
It is the most convenient way of creating `Sprite` objects.
It takes two arguments, the `index` of the sprite, and the `length` of the animation.

        getSprite: (index, length = 1) -> new Sprite this, index, length

We can now freeze the prototype:

    }

    Object.freeze Sheet.prototype

…And that's the end!

Jelli Game Engine

#  Sheet  #

`Sheet()` generates sprite-sheets and manages their rendering on a `CanvasRenderingContext2D`.
It is packaged with `Sprite()`, which describes a single sprite on the sheet.

##  General functions  ##

The function `drawSprite()` is called by `Sprite`s and `Sheet`s in order to draw their images.
It is not exposed to the window.

    drawSprite = (sheet, start_index, context, x, y, frame = 0) ->

…That's a lot of arguments. Let's go through them:

- `sheet` is the `Sheet` from which to draw the sprite
- `start_index` gives us the index of the sprite within the sheet
- `context` is the `CanvasRenderingContext2D` on which to draw the sprite
- `x` is the x-coordinate of the top-left corner of the sprite
- `y` is the y-coordinate of the top-left corner of the sprite
- `frame` is merely there as a convenience: It increments start_index by its value

The first thing we do is make sure everything is typed correctly.
The `sheet` and `context`, clearly, need to be of a certain type in order for this to work.
If any of the other provided arguments aren't numbers, however, we can go ahead and reset them to zero.

        unless sheet instanceof Sheet and start_index < sheet.size and context instanceof CanvasRenderingContext2D then return
        if isNaN(start_index = Number(start_index)) then start_index = 0
        if isNaN(x = Number(x)) then x = 0
        if isNaN(y = Number(y)) then y = 0
        if isNaN(frame = Number(frame)) then frame = 0

Next, we need to find the horizontal (`i`) and vertical (`j`) position of the sprite on the sheet.
We can get this information from `start_index` with a little math:

        i = start_index % sheet.width
        j = Math.floor start_index / sheet.width

These two lines just make the image a little easier to access:

        source = sheet.source
        image = sheet.image

Now we have all we need to draw the sprite!
There is a HUGE `if`-statement that precedes the draw function, because we want to make sure that what we're drawing is actually there.
If it isn't, then obviously we can't draw anything.

        if (source instanceof HTMLImageElement and source.complete or source instanceof SVGImageElement or source instanceof HTMLCanvasElement or createImageBitmap? and (image instanceof ImageBitmap or source instanceof ImageBitmap)) and not isNaN(i) and not isNaN(j) and Number(width = sheet.sprite_width) and Number(height = sheet.sprite_height) then context.drawImage (if createImageBitmap? and image instanceof ImageBitmap then image else source), i * width, j * height, width, height, x, y, width, height

Let's go through what those did.
First, we make sure that the `Sheet` actually has an image associated with it:

-   `source instanceof HTMLImageElement and source.complete`—
    If the image source is an `<img>` element, then it needs to have finished loading.

-   `source instanceof SVGImageElement or source instanceof HTMLCanvasElement`—
    The source doesn't have to be an `<img>` element though! It can also be an `<svg>` or a `<canvas>`.

-   `createImageBitmap? and (image instanceof ImageBitmap or source instanceof ImageBitmap)`—
    Finally, the source can be an `ImageBitmap`.
    This isn't supported in all browsers, so we check to make sure `createImageBitmap` exists first.
    However, if `createImageBitmap` *is* supported, then `Sheet`s have a special property, `Sheet.image`, which might contain one, and this should be given preference.

We also need to make sure that the sprite exists on the sheet:

-   `not isNaN(i) and not isNaN(j)`—
    This makes sure that our indices are actually, y'know, numbers.

-   `Number(width = sheet.sprite_width) and Number(height = sheet.sprite_height)`—
    This makes sure that the `Sheet` has a non-zero width and height.
    It also sets the variables `width` and `height` to those values, for convenient access later.

Finally, we can draw the sprite.
Again, we preference `image` if it is defined.

##  Sprite  ##

The `Sprite` constructor creates a reference to a sprite on a sheet.
For efficiency's sake, it does *not* actually contain any of the image data associated with that sprite.
The constructor takes three arguments: `sheet`, which gives the sheet; `index`, which is the index of the sprite on the sheet; and `length`, which for animated sprites gives the length of the animation.

    Sprite = (sheet, index, length = 1) ->

If `index` or `length` aren't numbers, then we go ahead and set them to `0` and `1`, respectively.

        if isNaN(index = Number(index)) then index = 0
        if isNaN(length = Number(length)) then length = 0

Now we can set the properties.
Note that `draw` simply binds `drawSprite` to the given `Sheet` and `index`.

        @draw = drawSprite.bind(null, sheet, index)
        @height = if sheet instanceof Sheet then sheet.sprite_height else 0
        @index = index
        @frames = length
        @sheet = if sheet instanceof Sheet then sheet else null
        @width = if sheet instanceof Sheet then sheet.sprite_width else 0

Since `Sprite`s are just static references, they should be immutable:

        Object.freeze this

And we're done!

`Sprite`s are very simple, and because the `draw` function is bound above, they don't have a prototype.
For purposes of inheritance, however, I've thrown this minimal one together:

    Sprite.prototype = {draw: ->}
    Object.freeze Sprite.prototype

##  Sheet  ##

`Sheet`s associate images with data and methods to make them easily referencable as sprite-sheets.

###  The constructor  ###

The `Sheet` constructor only takes three arguments: `source`, which gives the source image for the sheet, `sprite_width`, which gives the width of the sprites, and `sprite_height`, which gives their height.
In doing so, it makes the assumption that sprites and sprite-sheets do not have any borders or padding.
(Because borders and padding result in larger download times for users, this restriction is considered acceptable, but it may be lifted at some time in the future.)

    Sheet = (source, sprite_width, sprite_height) ->

First, we need to handle the arguments.
If `source` isn't an image type that we recognize, we go ahead and set it to `null`.
And if the `sprite_width` or `sprite_height` aren't recognizable as numbers, we set them to 0.
(Note from the above that a `Sheet` with zero `sprite_width` or `sprite_height` cannot be drawn.)

        unless source instanceof HTMLImageElement or source instanceof SVGImageElement or source instanceof HTMLCanvasElement or createImageBitmap? and source instanceof ImageBitmap then source = null
        if isNaN(sprite_width = Number(sprite_width)) then sprite_width = 0
        if isNaN(sprite_height = Number(sprite_height)) then sprite_height = 0

Recall that we need to check for `createImageBitmap` before checking to see if the source is an `ImageBitmap`.

We can get the width and height of the image from one of two sources, depending on the source type.
All of the accepted types have `width` and `height` properties, which specify their dimensions.
However, `HTMLImageElement`s also have `naturalWidth` and `naturalHeight` properties, and these should be preferred for pixel-perfect rendering.

If for some reason we can't get *either* of these properties, then the `source_width` and `source_height` are set to zero.

        unless source? and not isNaN(source_width = Number(if source.naturalWidth? then source.naturalWidth else source.width)) then source_width = 0
        unless source? and not isNaN(source_height = Number(if source.naturalHeight? then source.naturalHeight else source.height)) then source_height = 0

We now have everything we need to define the properties.
Note that `width` and `height` are provided in sprite-units, not pixels.
If `sprite_width` or `sprite_height` are `0`, then the corresponding `width` and `height` are obviously `NaN`.

        @height = Math.floor source_height / sprite_height
        @source = source
        @sprite_height = sprite_height
        @sprite_width = sprite_width
        @width = Math.floor source_width / sprite_width

The `size` property is just `width` times `height`.

        @size = @width * @height

`ImageBitmap`s are optimized for drawing to the canvas.
If they are supported, we can pre-render the sprite-sheet and store this in the `image` property.

        if createImageBitmap? then (createImageBitmap source).then (image) => @image = image

Because `Sheet`s contain static images, it doesn't make sense for them to change after creation.
We freeze them:

        Object.freeze this

For convenience's sake, two static method has been defined for `Sheet` to let you draw arbitrary sprites.
These are largely intended for use with callbacks.

The first is called `draw`, and takes five arguments:

- `context`: A `CanvasRenderingContext2D`
- `sprite`: A `Sprite`
- `x`: The x-coordinate at which to draw the sprite
- `y`: The y-coordinate at which to draw the sprite
- `frame`: The frame of the animation which to draw

It maps onto `sprite.draw`:

    Sheet.draw = (context, sprite, x, y, frame = 0) -> if sprite instanceof Sprite then sprite.draw context, x, y, frame

The second is called `drawSheetAtIndex`, and also takes five arguments:

- `context`: A `CanvasRenderingContext2D`
- `sheet`: A `Sheet`
- `index`: The index of the sprite
- `x`: The x-coordinate at which to draw the sprite
- `y`: The y-coordinate at which to draw the sprite

It maps onto `sheet.drawIndex`:

    Sheet.drawSheetAtIndex = (context, sheet, index, x, y) -> if sheet instanceof Sheet then sheet.drawIndex context, index, x, y

Finally, the `Sprite` constructor is added to `Sheet` for later access:

    Sheet.Sprite = Sprite

And now we can make `Sheet` available to the window:

    window.Sheet = Sheet

##  The prototype  ##

The `Sheet` prototype is fairly minimal, consisting of only two functions.

    Sheet.prototype = {

The first, `drawIndex`, draws the sprite located at the given `index`.
It is little more than a repackaging of `drawSprite`.

        drawIndex: (context, index, x, y) -> drawSprite this, index, context, x, y

The second, `getSprite`, creates a new `Sprite` pointing to the given `index`.
It is the most convenient way of creating `Sprite` objects.
It takes two arguments, the `index` of the sprite, and the `length` of the animation.

        getSprite: (index, length = 1) -> new Sprite this, index, length

We can now freeze the prototype:

    }

    Object.freeze Sheet.prototype

…And that's the end!


0.0.16 Tidy tetracoords.litcoffee (4)

0.0.16 Tidy tetracoords.litcoffee (4)

tetraCoords()
=============

#### Calculates the coordinates of a tetrahedron’s vertices from 6 edge lengths

- __G__ The point on the tabletop furthest away from you
- __H__ The leftmost point touching the tabletop
- __I__ The rightmost point touching the tabletop
- __J__ The point in the middle, not touching the table

To watch and compile automatically:
```bash
coffee --watch --compile supplemental/tetracoords/tetracoords.litcoffee
```

#### `tetraCoords()`
- `a <number>`  the edge joining __G — H__
- `b <number>`  the edge joining __H — I__
- `c <number>`  the edge joining __I — G__
- `d <number>`  the edge joining __G — J__
- `e <number>`  the edge joining __J — H__
- `f <number>`  the edge joining __J — I__
- `<array>`     twelve numbers, representing (x,y,z) coords of __G, H, I and J__

Returns an array of vertex coordinates for a tetrahedron of given edge-lengths.

      window.tetraCoords = (a, b, c, d, e, f) ->
        M = 'tetraCoords()\n  '

Run basic validation of the six arguments.

        for name,arg of { a:a,b:b,c:c,d:d,e:e,f:f }
          if 'number' != typeof arg then throw TypeError "
            #{M}Argument `#{name}` is #{typeof arg} not number"
          if 9007199254740991 < arg or 0 > arg then throw RangeError "
            #{M}Argument `#{name}` is #{arg} not 0 or a +ve number < 2^53"

Initialize the output array, and place __G,__ (the point on the tabletop
furthest away from you) at the origin.

        out = [
          0 # [0] = Gx
          0 # [1] = Gy
          0 # [2] = Gz
        ]

Use the [law of cosines](https://goo.gl/8djIju) to find the angle (in radians)
of the corner opposite `b` on the tabletop. `cos B = (a² + c² − b²) / 2ac`

        oppB = Math.acos( (a*a + c*c - b*b) / (2*a*c) )

Calculate __H,__ the leftmost point touching the tabletop.

        out.push(
          Math.sin(oppB/2) * -a, # [3] = Hx
          0,                     # [4] = Hy
          Math.cos(oppB/2) * -a  # [5] = Hz
        )

Calculate __I,__ the rightmost point touching the tabletop.

        out.push(
          Math.sin(oppB/2) * c,  # [6] = Ix
          0,                     # [7] = Iy
          Math.cos(oppB/2) * -c  # [8] = Iz
        )

Use `trilaterate()` to calculate __J,__ the raised point in the middle.

        result = trilaterate(
          { x:0     , y:0, z:0     , r:d }, # p1
          { x:out[3], y:0, z:out[5], r:e }, # p2
          { x:out[6], y:0, z:out[8], r:f }  # p3
        )

Deal with an impossible tetrahedron.

        if null == result then throw RangeError "
          #{M}`#{a},#{b},#{c},#{d},#{e},#{f}` cannot be tetrahedron edges"

`trilaterate()` usually returns coords for __J__ above _and_ below the tabletop.

        if 2 == result.length
          out.push(
            result[1].x, #  [9] = Jx
            result[1].y, # [10] = Jy (`result[1]` is always +ve)
            result[1].z  # [11] = Jz
          )

If `trilaterate()` returns an object, we have a ‘flat’ tetrahedron

        else
          out.push(
            result.x,    #  [9] = Jx
            result.y,    # [10] = Jy (always 0)
            result.z     # [11] = Jz
          )

Move the tetrahedron coords so that the origin is roughly in the center.

        dy = -out[10] / 3 # third of height, `-Jy / 3`
        out[y] += dy for y in [1,4,7,10]
        dz = -(out[5] + out[8]) / 4 # half of average depth, `(Hz + Iz) / 2 / 2`
        out[z] += dz for z in [2,5,8,11]

Round results to 3 decimal places.

        out = (Math.round(coord * 1000) / 1000 for coord in out)

Convert to a neat string. @todo pass tetraCoords()` an argument to enable this

        out = (for coord in out
          coord  = (if 0 <= coord then ' ' else '') + coord
          pos = coord.indexOf '.'
          coord += (if -1 == pos then '.000' else '00')
          pos = coord.indexOf '.'
          coord = coord.slice 0, pos + 4
        )

Return the output array.

        out

tetraCoords()
=============

#### Calculates the coordinates of a tetrahedron’s vertices from 6 edge lengths

- __G__ The point on the tabletop furthest away from you
- __H__ The leftmost point touching the tabletop
- __I__ The rightmost point touching the tabletop
- __J__ The point in the middle, not touching the table

To watch and compile automatically:
```bash
coffee --watch --compile supplemental/tetracoords/tetracoords.litcoffee
```

#### `tetraCoords()`
- `a <number>`  the edge joining __G — H__
- `b <number>`  the edge joining __H — I__
- `c <number>`  the edge joining __I — G__
- `d <number>`  the edge joining __G — J__
- `e <number>`  the edge joining __J — H__
- `f <number>`  the edge joining __J — I__
- `<array>`     twelve numbers, representing (x,y,z) coords of __G, H, I and J__

      window.tetraCoords = (a, b, c, d, e, f) ->
        M = 'tetraCoords()\n  '

Run basic validation of the six arguments.

        for name,arg of { a:a,b:b,c:c,d:d,e:e,f:f }
          if 'number' != typeof arg then throw TypeError "
            #{M}Argument `#{name}` is #{typeof arg} not number"
          if 9007199254740991 < arg or 0 > arg then throw RangeError "
            #{M}Argument `#{name}` is #{arg} not 0 or a +ve number < 2^53"

Initialize the output array, and place __G,__ (the point on the tabletop
furthest away from you) at the origin.

        out = [
          0 # [0] = Gx
          0 # [1] = Gy
          0 # [2] = Gz
        ]

Use the [law of cosines](https://goo.gl/8djIju) to find the angle (in radians)
of the corner opposite `b` on the tabletop. `cos B = (a² + c² − b²) / 2ac`

        oppB = Math.acos( (a*a + c*c - b*b) / (2*a*c) )

Calculate __H,__ the leftmost point touching the tabletop.

        out.push(
          Math.sin(oppB/2) * -a, # [3] = Hx
          0,                     # [4] = Hy
          Math.cos(oppB/2) * -a  # [5] = Hz
        )

Calculate __I,__ the rightmost point touching the tabletop.

        out.push(
          Math.sin(oppB/2) * c,  # [6] = Ix
          0,                     # [7] = Iy
          Math.cos(oppB/2) * -c  # [8] = Iz
        )

Use `trilaterate()` to calculate __J,__ the raised point in the middle.

        result = trilaterate(
          { x:0     , y:0, z:0     , r:d }, # p1
          { x:out[3], y:0, z:out[5], r:e }, # p2
          { x:out[6], y:0, z:out[8], r:f }  # p3
        )

Deal with an impossible tetrahedron.

        if null == result then throw RangeError "
          #{M}`#{a},#{b},#{c},#{d},#{e},#{f}` cannot be tetrahedron edges"

`trilaterate()` usually returns coords for __J__ above _and_ below the tabletop.

        if 2 == result.length
          out.push(
            result[1].x, #  [9] = Jx
            result[1].y, # [10] = Jy (`result[1]` is always +ve)
            result[1].z  # [11] = Jz
          )

If `trilaterate()` returns an object, we have a ‘flat’ tetrahedron

        else
          out.push(
            result.x,    #  [9] = Jx
            result.y,    # [10] = Jy (always 0)
            result.z     # [11] = Jz
          )

Move the tetrahedron coords so that the origin is roughly in the center.

        dy = -out[10] / 3 # third of height, `-Jy / 3`
        out[y] += dy for y in [1,4,7,10]
        dz = -(out[5] + out[8]) / 4 # half of average depth, `(Hz + Iz) / 2 / 2`
        out[z] += dz for z in [2,5,8,11]

Round results to 3 decimal places.

        out = (Math.round(coord * 1000) / 1000 for coord in out)

Convert to a neat string. @todo pass tetraCoords()` an argument to enable this

        out = (for coord in out
          coord  = (if 0 <= coord then ' ' else '') + coord
          pos = coord.indexOf '.'
          coord += (if -1 == pos then '.000' else '00')
          pos = coord.indexOf '.'
          coord = coord.slice 0, pos + 4
        )

Return the output array.

        out


Remove random html/source reference

Remove random html/source reference

# /api/App Components/Batman.View

`Batman.View`s connect a batman.js app to the DOM. This includes rendering HTML, handling DOM events, and maintaining view bindings. `Batman.View` extends `Batman.Object`. When subclassing `Batman.View`, you can create reusable UI components by defining attributes of the new view:

- [`::source`](/docs/api/batman.view.html#prototype_accessor_source) or [`::html`](/docs/api/batman.view.html#prototype_accessor_html) define the view's HTML.
- [`@option`](/docs/api/batman.view.html#class_function_option) adds context-based initialization options.
- [`@filter`](/docs/api/batman.view.html#class_function_filter) adds custom view filters.
- [Lifecycle hooks](/docs/views.html) fire when the view is loaded, rendered, or destroyed.

For more information about views, see [the guide](/docs/views.html).

## Accessors and Event Handlers

[View bindings](/docs/api/batman.view_bindings.html) have access to the views they're rendered by, so custom views are a great place to define view-specific accessors and event handlers. Then, you can connect them to your HTML with view bindings. For example, define a view:

```coffeescript
class CoffeeView extends Batman.View
  @accessor 'coffeeOfTheDay', -> "Guatemalan"
  drinkCoffee: -> alert("Yum!!")
```

then apply it to some HTML:

```html
<div data-view='CoffeeView'>
  <span data-bind='coffeeOfTheDay'></span>
  <button data-event-click='drinkCoffee'> Take a sip! </button>
<div>
```

Data bindings look for keys on their closest views first, so these bindings will be handled by `CoffeeView`.

## ::constructor(options = {}) : Batman.View

Returns a new `Batman.View`. Since `Batman.View` extends `Batman.Object`, all `options` are mixed in to the new instance. Use this to override `html`, `node`, `superview`, `parentNode`, and/or your custom data.

## ::lookupKeypath(keypath : String)

Traverses up the view tree searching for `keypath` and returns the first
result or `undefined` if no match is found. The path it takes is:

current view → chain of superviews → layout view → active controller → app →
window

    test 'lookupKeypath returns the value if defined on the view or on an ancestor', ->
      superview = new Batman.View(cat: 'Meowie')
      subview = new Batman.View(superview: superview, dog: 'Fido')
      equal 'Fido', subview.lookupKeypath('dog'), "finds an accessor on itself"
      equal 'Meowie', subview.lookupKeypath('cat'), "finds an accessor on its superview"
      equal undefined, subview.lookupKeypath('bogusKeypath'), "returns undefined if the keypath isn't defined"

If used in an accessor, `keypath` is registered as source and will be correctly bound. `lookupKeypath` is used by [view bindings](/docs/api/batman.view_bindings.html) to get data.

## ::setKeypath(keypath, value)

Traverses the view tree searching for the specified keypath and sets the value
on the nearest ancestor which defines it. If no ancestor view defines the given
keypath, it will be set on the nearest ancestor which is not a
backing view.

`setKeypath` is used by [view bindings](/docs/api/batman.view_bindings.html) to set data.

    test 'setKeypath sets the value if defined on the view or on an ancestor', ->
      superview = new Batman.View(cat: 'Meowie')
      subview = new Batman.View(superview: superview, dog: 'Fido')
      subview.setKeypath('cat', 'Mittens')
      equal 'Mittens', superview.get('cat'), "updates an accessor on its superview"
      subview.setKeypath('dog', 'Lassie')
      equal 'Lassie', subview.get('dog'), "updates an accessor on itself"

    test 'setKeypath sets the value on the nearest non-backing view when not defined anywhere', ->
      superview = new Batman.View()
      view = new Batman.View(superview: superview)
      backingView = new Batman.BackingView(superview: view)

      backingView.setKeypath('animal', 'cat')
      equal 'cat', view.get('animal')

## ::%node : Node

Returns the DOM node that this view encapsulates.

Accessing `node` will load and parse the template if it isn't already
loaded.

    test 'node parses the template', ->
      view = new Batman.View(html: '
cat
')

      node = view.get('node')
      equal 'cat', node.firstChild.innerHTML

You can also access a view's `node` in its methods, for example, activating jQuery plugins:

```
class App.SearchBarView extends Batman.View
  viewDidAppear: ->
    $node = $(@get('node'))
    $node.typeahead() # <= whatever jQuery plugin you want!
```
## ::%source : String

This string will be used to fetch a view's HTML, relative to [`Batman.config.pathToHTML`](/docs/configuration.html).
You don't need to add `.html` to this string -- it will be added automatically.

Inside a controller action, batman.js provides a default source based on the
contoller's [`routingKey`](/docs/api/batman.controller.html#routingkey_and_minification) and the [controller action](/docs/api/batman.controller.html#actions).

You can set `source` in the class definition:

```
class App.HeaderNavigationView extends Batman.View
  source: 'layout/_header'
```

Or when calling `@render()` inside a controller action:

```
class App.PostsController extends Batman.Controller
  show: ->
    @set('post', new App.Post)
    if @get('post.isAlternative')
      @render(source: "posts/alternative_new")
    else
      @render() # defaults to 'posts/new'
```

## ::%html : String

The HTML source for the view's template. Setting this will parse the template
and build bindings automatically, but it will not be inserted into the DOM
until the view is added to a superview. You can specify a view's HTML when you define the class:

```
class App.SearchBarView extends Batman.View
  html: "<input type='text' placeholder='Enter a search term' />"
```

If you don't explicitly set `html` but you do set `source`, then getting `html`
will automatically fetch the template source from the local template store.

    test 'setting a source loads the correct template', ->
      Batman.View.store.set('/animals', '
cat
')
      view = new Batman.View(source: '/animals')

      node = view.get('node')
      equal 'cat', node.firstChild.innerHTML

## @filter(label : string, filter : function)

Defines a custom [view filter](/docs/api/batman.view_filters.html) for use within the `View`.

`filter` will be invoked with the pre-filter `value` and any arguments passed to the view filter. For example:

```coffeescript
class App.MultiplierView extends Batman.View
  @filter 'multiplyBy', (value, multiplier) -> value * multiplier
```

would handle:

```html
<div data-view='MultiplierView' data-context-amount='100'>
  <span data-bind='amount | multiplyBy 6'>
    <!-- would render to "600" -->
  </span>
</div>
```

_Note_: If the `View`'s HTML is loaded before the view is instantiated, this filter won't have been defined yet and batman.js will throw an error. Avoid this by defining your custom filter at app-level or by defining the `View`'s HTML with [`::source`](/docs/api/batman.view.html#prototype_accessor_source) or [`::html`](/docs/api/batman.view.html#prototype_accessor_html).

## @option(keys...)

Defines a custom option for the `View`. `@option` allows you to initialize your view with data from its context. For example:

```coffeescript
class App.MultiplierView extends Batman.View
  @option 'amount', 'multiplier'
  @accessor 'finalAmount', -> @get('amount') * @get('multiplier')
```

```html
<div data-view='MultiplierView' data-view-amount='10' data-view-multiplier='8'>
  <span data-bind='finalAmount'>
    <!-- would render to "80" !-->
  </span>
</div>
```

Options passed with `data-view-#{option}` may also be keypaths. Keypath changes will be tracked by the view.

## ::.superview : Batman.View

Returns the view's superview. Every view except an app's `LayoutView` has a superview.

## ::.subviews : Batman.Set

The set of direct children of this `View`. Since it's a [`Batman.Set`](/docs/api/batman.set.html), you can operate directly on this set and batman.js will automatically keep the DOM in sync.

Adding to a view's subviews will automatically update the tree and parse
the template and bindings. If the superview is in the DOM, this will
insert the current view's node into the DOM.

    test 'adding to a superview parses bindings', ->
      superview = new Batman.View()
      view = new Batman.View(html: '

', animal: 'cat')

      superview.subviews.add(view)
      equal 'cat', view.get('node').firstChild.innerHTML

Removing from a view's subviews will automatically remove the subview from
the DOM.

    test 'removing from the current superview removes the node from the DOM', ->
      superview = new Batman.View(html: '', parentNode: document.body)
      superview.get('node')
      view = new Batman.View(html: '', superview: superview)

      ok Batman.DOM.containsNode(superview.get('node'), view.get('node'))

      superview.subviews.remove(view)
      ok not Batman.DOM.containsNode(superview.get('node'), view.get('node'))

## ::removeFromSuperview()

Removes this view from its parent (and from the DOM), without killing it.

    test 'removing from the current superview removes the node from the DOM', ->
      superview = new Batman.View()
      view = new Batman.View(superview: superview)

      view.removeFromSuperview()
      ok not superview.subviews.has(view)

## ::die()

Kills this view, which renders it to forever unusable. This has the
following implications:

- The view is removed from its superview
- The view's node is removed from the DOM
- The view's bindings are destroyed
- The view's current subviews are killed

      test 'die kills the view', ->
        superview = new Batman.View()
        view = new Batman.View(superview: superview)

        view.die()
        equal true, view.isDead
        equal 0, superview.subviews.length

## ::.isDead : boolean

True if the view has been killed, false otherwise.

## ::destroySubviews()

Kills every subview of this view.

    test 'destroySubviews kills all subviews', ->
      superview = new Batman.View()
      one = new Batman.View(superview: superview)
      two = new Batman.View(superview: superview)

      superview.destroySubviews()
      ok one.isDead
      ok two.isDead

## ::propagateToSubviews(eventOrKey : string, value : Object)

If `value` is defined, set `eventOrKey` to `value` on the entire subtree.
Otherwise, fire `eventOrKey` on the entire subtree.

    test 'propagateToSubviews propagates events', ->
      superview = new Batman.View()
      one = new Batman.View(superview: superview)
      two = new Batman.View(superview: one)

      superview.on 'eventName', superSpy = createSpy()
      one.on 'eventName', oneSpy = createSpy()
      two.on 'eventName', twoSpy = createSpy()

      superview.propagateToSubviews('eventName')

      equal 1, superSpy.callCount
      equal 1, oneSpy.callCount
      equal 1, twoSpy.callCount

    test 'propagateToSubviews propagates keys', ->
      superview = new Batman.View()
      one = new Batman.View(superview: superview)
      two = new Batman.View(superview: one)

      superview.propagateToSubviews('key', 'value')

      equal superview.get('key'), 'value'
      equal one.get('key'), 'value'
      equal two.get('key'), 'value'

## @viewForNode(node, climbTree = true) : Batman.View

Finds the view acting as the current context for a node — i.e. perform the
reverse mapping of the view tree to the DOM. If you pass `false` for
`climbTree`, it won't traverse up the DOM, and will return `undefined` unless
the node is the view's root.

# /api/App Components/Batman.View

`Batman.View`s connect a batman.js app to the DOM. This includes rendering HTML, handling DOM events, and maintaining view bindings. `Batman.View` extends `Batman.Object`. When subclassing `Batman.View`, you can create reusable UI components by defining attributes of the new view:

- [`::source`](/docs/api/batman.view.html#prototype_accessor_source) or [`::html`](/docs/api/batman.view.html#prototype_accessor_html) define the view's HTML.
- [`@option`](/docs/api/batman.view.html#class_function_option) adds context-based initialization options.
- [`@filter`](/docs/api/batman.view.html#class_function_filter) adds custom view filters.
- [Lifecycle hooks](/docs/views.html) fire when the view is loaded, rendered, or destroyed.

For more information about views, see [the guide](/docs/views.html).

## Accessors and Event Handlers

[View bindings](/docs/api/batman.view_bindings.html) have access to the views they're rendered by, so custom views are a great place to define view-specific accessors and event handlers. Then, you can connect them to your HTML with view bindings. For example, define a view:

```coffeescript
class CoffeeView extends Batman.View
  @accessor 'coffeeOfTheDay', -> "Guatemalan"
  drinkCoffee: -> alert("Yum!!")
```

then apply it to some HTML:

```html
<div data-view='CoffeeView'>
  <span data-bind='coffeeOfTheDay'></span>
  <button data-event-click='drinkCoffee'> Take a sip! </button>
<div>
```

Data bindings look for keys on their closest views first, so these bindings will be handled by `CoffeeView`. If the HTML inside a custom view will always be the same, you can use [`::source`](/docs/api/batman.view.html#prototype_accessor_source) or [`::html`](/docs/api/batman.view.html#prototype_accessor_html) to define it.

## ::constructor(options = {}) : Batman.View

Returns a new `Batman.View`. Since `Batman.View` extends `Batman.Object`, all `options` are mixed in to the new instance. Use this to override `html`, `node`, `superview`, `parentNode`, and/or your custom data.

## ::lookupKeypath(keypath : String)

Traverses up the view tree searching for `keypath` and returns the first
result or `undefined` if no match is found. The path it takes is:

current view → chain of superviews → layout view → active controller → app →
window

    test 'lookupKeypath returns the value if defined on the view or on an ancestor', ->
      superview = new Batman.View(cat: 'Meowie')
      subview = new Batman.View(superview: superview, dog: 'Fido')
      equal 'Fido', subview.lookupKeypath('dog'), "finds an accessor on itself"
      equal 'Meowie', subview.lookupKeypath('cat'), "finds an accessor on its superview"
      equal undefined, subview.lookupKeypath('bogusKeypath'), "returns undefined if the keypath isn't defined"

If used in an accessor, `keypath` is registered as source and will be correctly bound. `lookupKeypath` is used by [view bindings](/docs/api/batman.view_bindings.html) to get data.

## ::setKeypath(keypath, value)

Traverses the view tree searching for the specified keypath and sets the value
on the nearest ancestor which defines it. If no ancestor view defines the given
keypath, it will be set on the nearest ancestor which is not a
backing view.

`setKeypath` is used by [view bindings](/docs/api/batman.view_bindings.html) to set data.

    test 'setKeypath sets the value if defined on the view or on an ancestor', ->
      superview = new Batman.View(cat: 'Meowie')
      subview = new Batman.View(superview: superview, dog: 'Fido')
      subview.setKeypath('cat', 'Mittens')
      equal 'Mittens', superview.get('cat'), "updates an accessor on its superview"
      subview.setKeypath('dog', 'Lassie')
      equal 'Lassie', subview.get('dog'), "updates an accessor on itself"

    test 'setKeypath sets the value on the nearest non-backing view when not defined anywhere', ->
      superview = new Batman.View()
      view = new Batman.View(superview: superview)
      backingView = new Batman.BackingView(superview: view)

      backingView.setKeypath('animal', 'cat')
      equal 'cat', view.get('animal')

## ::%node : Node

Returns the DOM node that this view encapsulates.

Accessing `node` will load and parse the template if it isn't already
loaded.

    test 'node parses the template', ->
      view = new Batman.View(html: '
cat
')

      node = view.get('node')
      equal 'cat', node.firstChild.innerHTML

You can also access a view's `node` in its methods, for example, activating jQuery plugins:

```
class App.SearchBarView extends Batman.View
  viewDidAppear: ->
    $node = $(@get('node'))
    $node.typeahead() # <= whatever jQuery plugin you want!
```
## ::%source : String

This string will be used to fetch a view's HTML, relative to [`Batman.config.pathToHTML`](/docs/configuration.html).
You don't need to add `.html` to this string -- it will be added automatically.

Inside a controller action, batman.js provides a default source based on the
contoller's [`routingKey`](/docs/api/batman.controller.html#routingkey_and_minification) and the [controller action](/docs/api/batman.controller.html#actions).

You can set `source` in the class definition:

```
class App.HeaderNavigationView extends Batman.View
  source: 'layout/_header'
```

Or when calling `@render()` inside a controller action:

```
class App.PostsController extends Batman.Controller
  show: ->
    @set('post', new App.Post)
    if @get('post.isAlternative')
      @render(source: "posts/alternative_new")
    else
      @render() # defaults to 'posts/new'
```

## ::%html : String

The HTML source for the view's template. Setting this will parse the template
and build bindings automatically, but it will not be inserted into the DOM
until the view is added to a superview. You can specify a view's HTML when you define the class:

```
class App.SearchBarView extends Batman.View
  html: "<input type='text' placeholder='Enter a search term' />"
```

If you don't explicitly set `html` but you do set `source`, then getting `html`
will automatically fetch the template source from the local template store.

    test 'setting a source loads the correct template', ->
      Batman.View.store.set('/animals', '
cat
')
      view = new Batman.View(source: '/animals')

      node = view.get('node')
      equal 'cat', node.firstChild.innerHTML

## @filter(label : string, filter : function)

Defines a custom [view filter](/docs/api/batman.view_filters.html) for use within the `View`.

`filter` will be invoked with the pre-filter `value` and any arguments passed to the view filter. For example:

```coffeescript
class App.MultiplierView extends Batman.View
  @filter 'multiplyBy', (value, multiplier) -> value * multiplier
```

would handle:

```html
<div data-view='MultiplierView' data-context-amount='100'>
  <span data-bind='amount | multiplyBy 6'>
    <!-- would render to "600" -->
  </span>
</div>
```

_Note_: If the `View`'s HTML is loaded before the view is instantiated, this filter won't have been defined yet and batman.js will throw an error. Avoid this by defining your custom filter at app-level or by defining the `View`'s HTML with [`::source`](/docs/api/batman.view.html#prototype_accessor_source) or [`::html`](/docs/api/batman.view.html#prototype_accessor_html).

## @option(keys...)

Defines a custom option for the `View`. `@option` allows you to initialize your view with data from its context. For example:

```coffeescript
class App.MultiplierView extends Batman.View
  @option 'amount', 'multiplier'
  @accessor 'finalAmount', -> @get('amount') * @get('multiplier')
```

```html
<div data-view='MultiplierView' data-view-amount='10' data-view-multiplier='8'>
  <span data-bind='finalAmount'>
    <!-- would render to "80" !-->
  </span>
</div>
```

Options passed with `data-view-#{option}` may also be keypaths. Keypath changes will be tracked by the view.

## ::.superview : Batman.View

Returns the view's superview. Every view except an app's `LayoutView` has a superview.

## ::.subviews : Batman.Set

The set of direct children of this `View`. Since it's a [`Batman.Set`](/docs/api/batman.set.html), you can operate directly on this set and batman.js will automatically keep the DOM in sync.

Adding to a view's subviews will automatically update the tree and parse
the template and bindings. If the superview is in the DOM, this will
insert the current view's node into the DOM.

    test 'adding to a superview parses bindings', ->
      superview = new Batman.View()
      view = new Batman.View(html: '

', animal: 'cat')

      superview.subviews.add(view)
      equal 'cat', view.get('node').firstChild.innerHTML

Removing from a view's subviews will automatically remove the subview from
the DOM.

    test 'removing from the current superview removes the node from the DOM', ->
      superview = new Batman.View(html: '', parentNode: document.body)
      superview.get('node')
      view = new Batman.View(html: '', superview: superview)

      ok Batman.DOM.containsNode(superview.get('node'), view.get('node'))

      superview.subviews.remove(view)
      ok not Batman.DOM.containsNode(superview.get('node'), view.get('node'))

## ::removeFromSuperview()

Removes this view from its parent (and from the DOM), without killing it.

    test 'removing from the current superview removes the node from the DOM', ->
      superview = new Batman.View()
      view = new Batman.View(superview: superview)

      view.removeFromSuperview()
      ok not superview.subviews.has(view)

## ::die()

Kills this view, which renders it to forever unusable. This has the
following implications:

- The view is removed from its superview
- The view's node is removed from the DOM
- The view's bindings are destroyed
- The view's current subviews are killed

      test 'die kills the view', ->
        superview = new Batman.View()
        view = new Batman.View(superview: superview)

        view.die()
        equal true, view.isDead
        equal 0, superview.subviews.length

## ::.isDead : boolean

True if the view has been killed, false otherwise.

## ::destroySubviews()

Kills every subview of this view.

    test 'destroySubviews kills all subviews', ->
      superview = new Batman.View()
      one = new Batman.View(superview: superview)
      two = new Batman.View(superview: superview)

      superview.destroySubviews()
      ok one.isDead
      ok two.isDead

## ::propagateToSubviews(eventOrKey : string, value : Object)

If `value` is defined, set `eventOrKey` to `value` on the entire subtree.
Otherwise, fire `eventOrKey` on the entire subtree.

    test 'propagateToSubviews propagates events', ->
      superview = new Batman.View()
      one = new Batman.View(superview: superview)
      two = new Batman.View(superview: one)

      superview.on 'eventName', superSpy = createSpy()
      one.on 'eventName', oneSpy = createSpy()
      two.on 'eventName', twoSpy = createSpy()

      superview.propagateToSubviews('eventName')

      equal 1, superSpy.callCount
      equal 1, oneSpy.callCount
      equal 1, twoSpy.callCount

    test 'propagateToSubviews propagates keys', ->
      superview = new Batman.View()
      one = new Batman.View(superview: superview)
      two = new Batman.View(superview: one)

      superview.propagateToSubviews('key', 'value')

      equal superview.get('key'), 'value'
      equal one.get('key'), 'value'
      equal two.get('key'), 'value'

## @viewForNode(node, climbTree = true) : Batman.View

Finds the view acting as the current context for a node — i.e. perform the
reverse mapping of the view tree to the DOM. If you pass `false` for
`climbTree`, it won't traverse up the DOM, and will return `undefined` unless
the node is the view's root.