<commit_before>
/*
The MIT License (MIT)

Copyright (c) 2014 Rob Christian

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*

Semi-colons are just FUD. If your minifier can't handle this code, switch to one that is JS-compliant.

*/

;(function(){

  /*  Private Class Data  */

  var DEFINE = Object.defineProperty
  var OVERRIDE = function(object, method_name, method){
    DEFINE(object, method_name, { enumerable:false, configurable:false, value:method })
  }
  var _property_manipulator_
  var PROPERTY_MANIPULATOR = function(obj){
    if (! obj) return _property_manipulator_
    else _property_manipulator_ = obj
    return PROPERTY_MANIPULATOR
  }

  var _bindables = []
  var _events = new MicroEvent()

  /*  Bindable Classes  */

  function Bindable(data){
    if (typeOf(data) === 'Array')
      return new BindableArray(data)
    else if (familyOf(data) === 'complex')
      return new BindableObject(data)
  }

  function bind(){ //console.log('BIND', arguments)
    var setter_cb, property, parent, opts

    opts = Array.prototype.slice.call(arguments)

    if (opts.length === 3) {
      parent = opts[0]
      property = opts[1]
      setter_cb = opts[2]

      parent[property] = PROPERTY_MANIPULATOR({
        fetch:function(id){ _events.bind(id,setter_cb) }
      })
    }

    else if (typeOf(opts[0] === 'Array')) {
      setter_cb = opts[1]
      // opts[0]._array_events_ = PROPERTY_MANIPULATOR({
      //   fetch:function(id){ _events.bind(id,setter_cb) }
      // })
      _events.bind(opts[0]._id,setter_cb)
    }

  }

  function unbind(setter_cb){
    _events.unbind(setter_cb)
  }

  function recompute(data){
    if (familyOf(data) === 'complex')
      this.constructor.apply(this,data)
    return this
  }

  function BindableObject(data){ console.log(data)
    Object.keys(data).map(function(prop){
      this._new_property_ = [prop, data[prop]]
    }.bind(this))
  }
  DEFINE(BindableObject.prototype, 'bind', { enumerable:false, configurable:false, value:bind })
  DEFINE(BindableObject.prototype, 'unbind', { enumerable:false, configurable:false, value:unbind })
  DEFINE(BindableObject.prototype, 'recompute', { enumerable:false, configurable:false, value:recompute })
  DEFINE(BindableObject.prototype, 'onChange', { enumerable:false, configurable:false,
    value:function(props, cb){
      if (typeOf(props) !== 'Array') return
      props.forEach(function(prop){ bind(this,prop,cb) }.bind(this))
    }
  })
  DEFINE(BindableObject.prototype, '_new_property_', { enumerable:false, configurable:false,
    set:function(){ addProperty.apply(this, arguments) }
  })

  function BindableArray(array){
    var self = []

    DEFINE(self, '_id', { enumerable:false, configurable:false, value:+Math.random().toString().split('.')[1] })
    DEFINE(self, '_timeout', { enumerable:false, configurable:false, value:60 })
    DEFINE(self, 'bind', { enumerable:false, configurable:false, value:bind })
    DEFINE(self, 'unbind', { enumerable:false, configurable:false, value:unbind })
    DEFINE(self, 'recompute', { enumerable:false, configurable:false, value:recompute })
    DEFINE(self, '_new_property_', { enumerable:false, configurable:false,
      set:function(){ addProperty.apply(self, arguments) }
    })
    DEFINE(self, '_array_events_', { enumerable:false, configurable:false,
      set:function(manipulator){
        if (manipulator === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().fetch)
          PROPERTY_MANIPULATOR().fetch(self._id)
      }
    })
    OVERRIDE(self, 'push', function(obj){

      self._new_property_ = [self.length, obj]
      debounce(self._timeout, 'push'+self._id, function(){
        _events.trigger(self._id, [self.length-1, self[self.length-1]], 'push')
        console.log( 'emit: push'+self._id )
      })

    })
    OVERRIDE(self, 'pop', function(){

      var r = self[self.length-1]
      self.length = self.length-1
      debounce(self._timeout, 'pop'+self._id, function(){
        _events.trigger(self._id, r, 'pop')
        console.log( 'emit: pop'+self._id )
      })
      return r

    })
    OVERRIDE(self, 'shift', function(){

      var r = self[0]
      Object.keys(self).map(function(idx){
        self[+idx] = self[+idx+1]
        self[+idx] = PROPERTY_MANIPULATOR({
          fetch:function(id){ self[+idx] = PROPERTY_MANIPULATOR({id:id}) }
        })
      })
      self.length = self.length-1
      debounce(self._timeout, 'shift'+self._id, function(){
        _events.trigger(self._id, r, 'shift')
        console.log( 'emit: shift'+self._id )
      })
      return r

    })
    OVERRIDE(self, 'unshift', function(obj){

      Object.keys(self).reverse().map(function(idx){
        console.log(+idx+1, +idx)
        self._new_property_ = [+idx+1, self[+idx]]
        self[+idx] = PROPERTY_MANIPULATOR({
          fetch:function(id){ self[+idx+1] = PROPERTY_MANIPULATOR({id:id}) }
        })
      })
      self._new_property_ = [0, obj]
      debounce(self._timeout, 'unshift'+self._id, function(){
        _events.trigger(self._id, self, 'unshift')
        console.log( 'emit: unshift'+self._id )
      })
      return self.length

    })
    OVERRIDE(self, 'splice', function(){

      debounce(self._timeout, 'splice'+self._id, function(){
        _events.trigger(self._id, self, 'splice')
        console.log( 'emit: splice'+self._id )
      })
      Array.prototype.splice.apply(self, arguments)

    })
    OVERRIDE(self, 'slice', function(){

      Array.prototype.slice.apply(self, arguments)
      debounce(self._timeout, 'slice'+self._id, function(){
        _events.trigger(self._id, self, 'slice')
        console.log( 'emit: slice'+self._id )
      })

    })
    OVERRIDE(self, 'reverse', function(idx1, idx2){ // This works, but it's not optimized yet.

      for (var l=0; l < Math.floor(self.length/2); l++) {
        // Method 1 is this.
        var r = self.length-1 - l
        self[r] = PROPERTY_MANIPULATOR({ fetch:function(r_id){
          self[l] = PROPERTY_MANIPULATOR({ fetch:function(l_id){
            self[r] = PROPERTY_MANIPULATOR({id:l_id})
            self[l] = PROPERTY_MANIPULATOR({id:r_id})
          }})
        }})
        // Method 2 would be something like this.
        // Array.prototype.push.call(self, self[ length ])
        // Array.prototype.splice.call(self, length, 1)
      }
      Array.prototype.reverse.call(self)
      debounce(self._timeout, 'reverse'+self._id, function(){
        _events.trigger(self._id, self, 'reverse')
        console.log( 'emit: reverse'+self._id )
      })
      return self

    })
    OVERRIDE(self, 'concat', function(arr){

      // This method is not implemented according to the standard, as it modifies the object it's being called upon.
      // In the future we'll aim to fix this, making it conform to the standard.

      if (typeOf(arr) === 'Array' && arr.length) {
        Object.keys(arr).map(function(key){
          self._new_property_ = [self.length, arr[key]]
        })
      }
      debounce(self._timeout, 'concat'+self._id, function(){
        _events.trigger(self._id, self, 'concat')
        console.log( 'emit: concat'+self._id )
      })
      return self

    })
    Object.keys(array).map(function(idx){
      self._new_property_ = [+idx, array[+idx]]
    })
    return self

  }

  function addProperty(args){
    var _val, _id, key, val
    _id = +Math.random().toString().split('.')[1]

    if (typeOf(args) === 'Array') {
      key = args[0]
      val = args[1]
    } else {
      console.log('Abort! Bad property assignment:',args)
      return
    }
    // console.log('addProperty', key, val)

    DEFINE(this, key, {
      enumerable: true
    , configurable: true
    , get: function(){ return _val }
    , set: function(value){
        if (value === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().fetch) {
          PROPERTY_MANIPULATOR().fetch(_id)
        }
        // else if (value === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().updated) {
        //   // if (typeOf(_val) === 'complex') _val = PROPERTY_MANIPULATOR({updated:true})
        //   // else _events.trigger(_id, _val)
        // }
        else if (value === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().id) {
          _id = PROPERTY_MANIPULATOR().id
        }
        else if (familyOf(value) === 'complex') {
          _val = new Bindable(value)
          _events.trigger(_id, _val)
        }
        else {
          _val = value
          _events.trigger(_id, _val)
        }
      }
    })
    this[key] = val
  }

  /* Takes a form DOM object and a Binding object, and does the rest for you. */

  function bindForm(form, bindable){

    ;[].forEach.call(form.querySelectorAll('input'), function(field){

      if (field.name in bindable) {
        fieldManager(function(input_handler, output_handler){

          field.addEventListener('input', function(ev){
            var do_it = function(){ bindable[field.name] = ev.target.value }
            input_handler( do_it )
          })

          bindable.bind(bindable, field.name, function(val){
            var do_it = function(){ field.value = val }
            output_handler( do_it )
          })

        })

        field.value = bindable[field.name]
      }

    })
  }

  /* Inverts control: Prevents inputs from receiving updates while they are the sender. */

  function fieldManager(receive_handlers){
    var _sent_by_me = false

    function input_handler(do_it){
      _sent_by_me = true
      do_it()
    }
    function output_handler(do_it){
      _sent_by_me ? _sent_by_me = false : do_it()
    }
    receive_handlers( input_handler, output_handler )
  }

  /* Our entry point for creating bindable objects, keeps a reference to the object created. */

  function NewBindable(data){
    var bindable = new Bindable(data)
    _bindables.push(bindable)
    return bindable
  }

  /*  HELPERS  */

  function familyOf(thing){
    var type = typeOf(thing)
    if (type) {
      return ({
        Date: 'simple'
      , String: 'simple'
      , Number: 'simple'
      , Boolean: 'simple'
      , Function: 'simple'
      , RegExp: 'simple'
      , Array: 'complex'
      , Object: 'complex'
      , HTMLElement: 'complex'
      , 'undefined': 'falsey'
      , 'null': 'falsey'
      })[type] || 'complex'
      // })[type] || (/^HTML\w*Element$/g.test(type) ? 'HTMLElement' : 'complex')
    } else {
      return false
    }
  }

  function typeOf(thing){
    if (typeof thing === 'number') return isNaN(thing) ? 'NaN' : 'Number'
    else if (thing instanceof HTMLElement) return 'HTMLElement'
    else return (thing !== null && thing !== undefined && thing.constructor) ? getObjectClass(thing) : '' + thing
  }

  function getObjectClass(obj) {
    if (obj && obj.constructor && obj.constructor.toString) {
      var arr = obj.constructor.toString().match(/function\s+(\w+)/)

      if (arr && arr.length == 2) return arr[1]
    }
    return undefined
  }

  var debounce
  ;(function(){
    var bounced = {}
    debounce = function(t, id, cb){
      clearTimeout( bounced[id] )
      bounced[id] = setTimeout(cb, t)
    }
  })()

  NewBindable.fieldManager = fieldManager
  NewBindable.bindForm = bindForm
  NewBindable.unbind = unbind
  NewBindable.bind = bind

  DEFINE(NewBindable, 'bindables', {get:function(){return _bindables}, enumerable:true})
  DEFINE(NewBindable, 'PROPERTY_MANIPULATOR', {value:PROPERTY_MANIPULATOR, writeable:false})

  if (typeof module !== 'undefined' && module.hasOwnProperty('exports')) {
    module.exports = NewBindable
  } else {
    window.Connected  = NewBindable
    window.Bindable   = Bindable
    window.familyOf   = familyOf
    window.typeOf     = typeOf
  }

})()
<commit_msg>Revamp getObjectClass logic.<commit_after>
/*
The MIT License (MIT)

Copyright (c) 2014 Rob Christian

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/*

Semi-colons are just FUD. If your minifier can't handle this code, switch to one that is JS-compliant.

*/

;(function(){

  /*  Private Class Data  */

  var DEFINE = Object.defineProperty
  var OVERRIDE = function(object, method_name, method){
    DEFINE(object, method_name, { enumerable:false, configurable:false, value:method })
  }
  var _property_manipulator_
  var PROPERTY_MANIPULATOR = function(obj){
    if (! obj) return _property_manipulator_
    else _property_manipulator_ = obj
    return PROPERTY_MANIPULATOR
  }

  var _bindables = []
  var _events = new MicroEvent()

  /*  Bindable Classes  */

  function Bindable(data){
    if (typeOf(data) === 'Array')
      return new BindableArray(data)
    else if (familyOf(data) === 'complex')
      return new BindableObject(data)
  }

  function bind(){ //console.log('BIND', arguments)
    var setter_cb, property, parent, opts

    opts = Array.prototype.slice.call(arguments)

    if (opts.length === 3) {
      parent = opts[0]
      property = opts[1]
      setter_cb = opts[2]

      parent[property] = PROPERTY_MANIPULATOR({
        fetch:function(id){ _events.bind(id,setter_cb) }
      })
    }

    else if (typeOf(opts[0] === 'Array')) {
      setter_cb = opts[1]
      // opts[0]._array_events_ = PROPERTY_MANIPULATOR({
      //   fetch:function(id){ _events.bind(id,setter_cb) }
      // })
      _events.bind(opts[0]._id,setter_cb)
    }

  }

  function unbind(setter_cb){
    _events.unbind(setter_cb)
  }

  function recompute(data){
    if (familyOf(data) === 'complex')
      this.constructor.apply(this,data)
    return this
  }

  function BindableObject(data){ console.log(data)
    Object.keys(data).map(function(prop){
      this._new_property_ = [prop, data[prop]]
    }.bind(this))
  }
  DEFINE(BindableObject.prototype, 'bind', { enumerable:false, configurable:false, value:bind })
  DEFINE(BindableObject.prototype, 'unbind', { enumerable:false, configurable:false, value:unbind })
  DEFINE(BindableObject.prototype, 'recompute', { enumerable:false, configurable:false, value:recompute })
  DEFINE(BindableObject.prototype, 'onChange', { enumerable:false, configurable:false,
    value:function(props, cb){
      if (typeOf(props) !== 'Array') return
      props.forEach(function(prop){ bind(this,prop,cb) }.bind(this))
    }
  })
  DEFINE(BindableObject.prototype, '_new_property_', { enumerable:false, configurable:false,
    set:function(){ addProperty.apply(this, arguments) }
  })

  function BindableArray(array){
    var self = []

    DEFINE(self, '_id', { enumerable:false, configurable:false, value:+Math.random().toString().split('.')[1] })
    DEFINE(self, '_timeout', { enumerable:false, configurable:false, value:60 })
    DEFINE(self, 'bind', { enumerable:false, configurable:false, value:bind })
    DEFINE(self, 'unbind', { enumerable:false, configurable:false, value:unbind })
    DEFINE(self, 'recompute', { enumerable:false, configurable:false, value:recompute })
    DEFINE(self, '_new_property_', { enumerable:false, configurable:false,
      set:function(){ addProperty.apply(self, arguments) }
    })
    DEFINE(self, '_array_events_', { enumerable:false, configurable:false,
      set:function(manipulator){
        if (manipulator === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().fetch)
          PROPERTY_MANIPULATOR().fetch(self._id)
      }
    })
    OVERRIDE(self, 'push', function(obj){

      self._new_property_ = [self.length, obj]
      debounce(self._timeout, 'push'+self._id, function(){
        _events.trigger(self._id, [self.length-1, self[self.length-1]], 'push')
        console.log( 'emit: push'+self._id )
      })

    })
    OVERRIDE(self, 'pop', function(){

      var r = self[self.length-1]
      self.length = self.length-1
      debounce(self._timeout, 'pop'+self._id, function(){
        _events.trigger(self._id, r, 'pop')
        console.log( 'emit: pop'+self._id )
      })
      return r

    })
    OVERRIDE(self, 'shift', function(){

      var r = self[0]
      Object.keys(self).map(function(idx){
        self[+idx] = self[+idx+1]
        self[+idx] = PROPERTY_MANIPULATOR({
          fetch:function(id){ self[+idx] = PROPERTY_MANIPULATOR({id:id}) }
        })
      })
      self.length = self.length-1
      debounce(self._timeout, 'shift'+self._id, function(){
        _events.trigger(self._id, r, 'shift')
        console.log( 'emit: shift'+self._id )
      })
      return r

    })
    OVERRIDE(self, 'unshift', function(obj){

      Object.keys(self).reverse().map(function(idx){
        console.log(+idx+1, +idx)
        self._new_property_ = [+idx+1, self[+idx]]
        self[+idx] = PROPERTY_MANIPULATOR({
          fetch:function(id){ self[+idx+1] = PROPERTY_MANIPULATOR({id:id}) }
        })
      })
      self._new_property_ = [0, obj]
      debounce(self._timeout, 'unshift'+self._id, function(){
        _events.trigger(self._id, self, 'unshift')
        console.log( 'emit: unshift'+self._id )
      })
      return self.length

    })
    OVERRIDE(self, 'splice', function(){

      debounce(self._timeout, 'splice'+self._id, function(){
        _events.trigger(self._id, self, 'splice')
        console.log( 'emit: splice'+self._id )
      })
      Array.prototype.splice.apply(self, arguments)

    })
    OVERRIDE(self, 'slice', function(){

      Array.prototype.slice.apply(self, arguments)
      debounce(self._timeout, 'slice'+self._id, function(){
        _events.trigger(self._id, self, 'slice')
        console.log( 'emit: slice'+self._id )
      })

    })
    OVERRIDE(self, 'reverse', function(idx1, idx2){ // This works, but it's not optimized yet.

      for (var l=0; l < Math.floor(self.length/2); l++) {
        // Method 1 is this.
        var r = self.length-1 - l
        self[r] = PROPERTY_MANIPULATOR({ fetch:function(r_id){
          self[l] = PROPERTY_MANIPULATOR({ fetch:function(l_id){
            self[r] = PROPERTY_MANIPULATOR({id:l_id})
            self[l] = PROPERTY_MANIPULATOR({id:r_id})
          }})
        }})
        // Method 2 would be something like this.
        // Array.prototype.push.call(self, self[ length ])
        // Array.prototype.splice.call(self, length, 1)
      }
      Array.prototype.reverse.call(self)
      debounce(self._timeout, 'reverse'+self._id, function(){
        _events.trigger(self._id, self, 'reverse')
        console.log( 'emit: reverse'+self._id )
      })
      return self

    })
    OVERRIDE(self, 'concat', function(arr){

      // This method is not implemented according to the standard, as it modifies the object it's being called upon.
      // In the future we'll aim to fix this, making it conform to the standard.

      if (typeOf(arr) === 'Array' && arr.length) {
        Object.keys(arr).map(function(key){
          self._new_property_ = [self.length, arr[key]]
        })
      }
      debounce(self._timeout, 'concat'+self._id, function(){
        _events.trigger(self._id, self, 'concat')
        console.log( 'emit: concat'+self._id )
      })
      return self

    })
    Object.keys(array).map(function(idx){
      self._new_property_ = [+idx, array[+idx]]
    })
    return self

  }

  function addProperty(args){
    var _val, _id, key, val
    _id = +Math.random().toString().split('.')[1]

    if (typeOf(args) === 'Array') {
      key = args[0]
      val = args[1]
    } else {
      console.log('Abort! Bad property assignment:',args)
      return
    }
    // console.log('addProperty', key, val)

    DEFINE(this, key, {
      enumerable: true
    , configurable: true
    , get: function(){ return _val }
    , set: function(value){
        if (value === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().fetch) {
          PROPERTY_MANIPULATOR().fetch(_id)
        }
        // else if (value === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().updated) {
        //   // if (typeOf(_val) === 'complex') _val = PROPERTY_MANIPULATOR({updated:true})
        //   // else _events.trigger(_id, _val)
        // }
        else if (value === PROPERTY_MANIPULATOR && PROPERTY_MANIPULATOR().id) {
          _id = PROPERTY_MANIPULATOR().id
        }
        else if (familyOf(value) === 'complex') {
          _val = new Bindable(value)
          _events.trigger(_id, _val)
        }
        else {
          _val = value
          _events.trigger(_id, _val)
        }
      }
    })
    this[key] = val
  }

  /* Takes a form DOM object and a Binding object, and does the rest for you. */

  function bindForm(form, bindable){

    ;[].forEach.call(form.querySelectorAll('input'), function(field){

      if (field.name in bindable) {
        fieldManager(function(input_handler, output_handler){

          field.addEventListener('input', function(ev){
            var do_it = function(){ bindable[field.name] = ev.target.value }
            input_handler( do_it )
          })

          bindable.bind(bindable, field.name, function(val){
            var do_it = function(){ field.value = val }
            output_handler( do_it )
          })

        })

        field.value = bindable[field.name]
      }

    })
  }

  /* Inverts control: Prevents inputs from receiving updates while they are the sender. */

  function fieldManager(receive_handlers){
    var _sent_by_me = false

    function input_handler(do_it){
      _sent_by_me = true
      do_it()
    }
    function output_handler(do_it){
      _sent_by_me ? _sent_by_me = false : do_it()
    }
    receive_handlers( input_handler, output_handler )
  }

  /* Our entry point for creating bindable objects, keeps a reference to the object created. */

  function NewBindable(data){
    var bindable = new Bindable(data)
    _bindables.push(bindable)
    return bindable
  }

  /*  HELPERS  */

  function familyOf(thing){
    var type = typeOf(thing)
    if (type) {
      return ({
        Date: 'simple'
      , String: 'simple'
      , Number: 'simple'
      , Boolean: 'simple'
      , Function: 'simple'
      , RegExp: 'simple'
      , Array: 'complex'
      , Object: 'complex'
      , HTMLElement: 'complex'
      , 'undefined': 'falsey'
      , 'null': 'falsey'
      })[type] || 'complex'
      // })[type] || (/^HTML\w*Element$/g.test(type) ? 'HTMLElement' : 'complex')
    } else {
      return false
    }
  }

  function typeOf(thing){
    if (typeof thing === 'number') return isNaN(thing) ? 'NaN' : 'Number'
    else if (thing instanceof HTMLElement) return 'HTMLElement'
    else return (thing !== null && thing !== undefined && thing.constructor) ? getObjectClass(thing) : '' + thing
  }

  function getObjectClass(obj) {
    var string
    if (obj.constructor && obj.constructor.toString) string = obj.constructor.toString()
    else throw new Error('Object constructor does not have toString method.')

    return (/function\s+(\w+)/.test(string)) ? string.match(/function\s+(\w+)/)[1] : 'Anonymous Class'
  }

  var debounce
  ;(function(){
    var bounced = {}
    debounce = function(t, id, cb){
      clearTimeout( bounced[id] )
      bounced[id] = setTimeout(cb, t)
    }
  })()

  NewBindable.fieldManager = fieldManager
  NewBindable.bindForm = bindForm
  NewBindable.unbind = unbind
  NewBindable.bind = bind

  DEFINE(NewBindable, 'bindables', {get:function(){return _bindables}, enumerable:true})
  DEFINE(NewBindable, 'PROPERTY_MANIPULATOR', {value:PROPERTY_MANIPULATOR, writeable:false})

  if (typeof module !== 'undefined' && module.hasOwnProperty('exports')) {
    module.exports = NewBindable
  } else {
    window.Connected  = NewBindable
    window.Bindable   = Bindable
    window.familyOf   = familyOf
    window.typeOf     = typeOf
  }

})()
<|endoftext|>


<commit_before>/*******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2014 Fraunhofer FOKUS
 *******************************************************************************/

module.exports = {
	CERTIFICATE_LOCATION : "~/.ocdb/",
	REQUIRED_MIMETYPE : "application/json",
	FILE_ENDPOINTS : "./endpoints",
	LOCATION_RESOURCES : "./resources/",
	SERVER_PORT : 443,
	BASEURL_PATH : "/",
	API_VERSION : "v1",
	SESSION_LEASE : 900000,
	ERROR_OK : "ok",
	ERROR_WRONG_MIMETYPE : "wrong_mimetype",
	ERROR_METHOD_NOT_ALLOWED : "method_not_allowed",
	ERROR_NOT_FOUND : "resource_not_found",
	ERROR_CONFLICT : "resource_conflict",
	ERROR_REQUEST_INVALID : "request_invalid",
	ERROR_REQUEST_UNAUTHORIZED : "request_unauthorized",
	ERROR_INTERNAL : "internal_server_error"
}<commit_msg>Set default lease to a higher value.<commit_after>/*******************************************************************************
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Copyright 2014 Fraunhofer FOKUS
 *******************************************************************************/

module.exports = {
	CERTIFICATE_LOCATION : "~/.ocdb/",
	REQUIRED_MIMETYPE : "application/json",
	FILE_ENDPOINTS : "./endpoints",
	LOCATION_RESOURCES : "./resources/",
	SERVER_PORT : 443,
	BASEURL_PATH : "/",
	API_VERSION : "v1",
	SESSION_LEASE : 43200000,
	ERROR_OK : "ok",
	ERROR_WRONG_MIMETYPE : "wrong_mimetype",
	ERROR_METHOD_NOT_ALLOWED : "method_not_allowed",
	ERROR_NOT_FOUND : "resource_not_found",
	ERROR_CONFLICT : "resource_conflict",
	ERROR_REQUEST_INVALID : "request_invalid",
	ERROR_REQUEST_UNAUTHORIZED : "request_unauthorized",
	ERROR_INTERNAL : "internal_server_error"
}
<|endoftext|>


<commit_before>function Container( image, name, id ) {
	this.image = image;
	this.name  = name;
	if(!id) {
		result = create({'Image':this.image}, null, null, this.name);
		this.ID = result.ID
	} else {
		this.ID = id
	}
}

Container.prototype.run = function() {
	result = run(this.ID);
}

Container.prototype.on = function(eventtype, callback) {
	listen( this.ID, eventtype, callback );
}

Container.all = function() {
	return list()
}

Container.match = function(predicate) {
	result = []
	containers = Container.all();
	for( i = 0; i < containers.length; i++) {
		if( predicate(containers[i]) ) {
			result.push( containers[i] )
		}
	}
	return result;
}

Container.findByID = function(id) {
	c = Container.match(function(container) {
		return container.ID.indexOf(id) == 0;
	})[0]

	if( c == null ) {
		return null
	}

	result = new Container( c.Image, c.Names[0], c.ID );
	return result
}

<commit_msg>Make all() return container objects rather than raw docker object<commit_after>function Container( image, name, id ) {
	this.image = image;
	this.name  = name;
	if(!id) {
		result = create({'Image':this.image}, null, null, this.name);
		this.ID = result.ID
	} else {
		this.ID = id
	}
}

Container.prototype.run = function() {
	result = run(this.ID);
}

Container.prototype.on = function(eventtype, callback) {
	listen( this.ID, eventtype, callback );
}

Container.all = function() {
	containers = list();
	results = [];
	for( i = 0; i < containers.length; i++ ) {
		results.push( new Container(containers[i].Image, containers[i].Names[0], containers[i].ID));
	}
	return results
}

Container.match = function(predicate) {
	result = []
	containers = Container.all();
	for( i = 0; i < containers.length; i++) {
		if( predicate(containers[i]) ) {
			result.push( containers[i] )
		}
	}
	return result;
}

Container.findByID = function(id) {
	c = Container.match(function(container) {
		return container.ID.indexOf(id) == 0;
	})[0]

	if( c == null ) {
		return null
	}

	result = new Container( c.Image, c.Names[0], c.ID );
	return result
}

<|endoftext|>


<commit_before>// ==UserScript==
// @id             iitc-plugin-dynamic-scoreboard@Costaspap
// @name           IITC plugin: Create a local scoreboard
// @category       Info
// @version        0.1.0.20140524.214738
// @namespace      https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL      https://secure.jonatkins.com/iitc/release/plugins/dynamic-scoreboard.meta.js
// @downloadURL    https://secure.jonatkins.com/iitc/release/plugins/dynamic-scoreboard.user.js
// @description    Display a scoreboard about all visible portals with statistics about both teams,like average portal level,link & field counts etc.
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @grant          none
// ==/UserScript==

// A plug in by Costaspap and harisbitsakou
function wrapper(plugin_info) {
    // ensure plugin framework is there, even if iitc is not yet loaded
    if(typeof window.plugin !== 'function') window.plugin = function() {};

    //PLUGIN AUTHORS: writing a plugin outside of the IITC build environment? if so, delete these lines!!
    //(leaving them in place might break the 'About IITC' page or break update checks)
    plugin_info.buildName = 'jonatkins';
    plugin_info.dateTimeVersion = '20140524.214738';
    plugin_info.pluginId = 'dynamic-scoreboard';
    //END PLUGIN AUTHORS NOTE

    // PLUGIN START //

    // use own namespace for plugin
    window.plugin.scoreboard = function() {};

    //gets data of all the visible portals on the screen
    window.plugin.scoreboard.getPortals = function() {

        var retval=false;

        var displayBounds = map.getBounds();

        window.plugin.scoreboard.enlP = 0;
        window.plugin.scoreboard.resP = 0;
        window.plugin.scoreboard.enlEightLevelP = 0;
        window.plugin.scoreboard.resEightLevelP = 0;
        window.plugin.scoreboard.enlPorLevels = 0;
        window.plugin.scoreboard.resPorLevels = 0;
        window.plugin.scoreboard.maxEnl=0;
        window.plugin.scoreboard.maxRes=0;
        window.plugin.scoreboard.healthEnl = 0;
        window.plugin.scoreboard.healthRes = 0;

         //get all portals on screen
        $.each(window.portals, function(i, portal) {
            // eliminate offscreen portals (selected, and in padding)
            if(!displayBounds.contains(portal.getLatLng())) return true;
            //if there are any portals return true
            retval=true;

			//variable that contains portal data
            var d = portal.options.data;

			//variable that contains each portal's team value
            var teamN = portal.options.team;

            switch (teamN) {
                case TEAM_RES:  //if the portal is captured by the resistance,increase each counter's value for resistance counters
                    window.plugin.scoreboard.healthRes += d.health;
                    window.plugin.scoreboard.resP++;
                    window.plugin.scoreboard.resPorLevels = window.plugin.scoreboard.resPorLevels + portal.options.level;
                    if(portal.options.level===8){window.plugin.scoreboard.resEightLevelP++;}
                    if(portal.options.level>window.plugin.scoreboard.maxRes){window.plugin.scoreboard.maxRes = portal.options.level;}
                    break;
                case TEAM_ENL: //if the portal is captured by the enlightened,increase each counter's value for enlightened counters
                    window.plugin.scoreboard.healthEnl += d.health;
                    window.plugin.scoreboard.enlP++;
                    window.plugin.scoreboard.enlPorLevels = window.plugin.scoreboard.enlPorLevels + portal.options.level;
                    if(portal.options.level===8){window.plugin.scoreboard.enlEightLevelP++;}
                    if(portal.options.level>window.plugin.scoreboard.maxEnl){window.plugin.scoreboard.maxEnl = portal.options.level;}
                    break;
            }

        });

        return retval;
    }

	// The final function that displays the scoreboard by calling the portalTable function
    window.plugin.scoreboard.displayScoreboard = function() {
        var html = '';

        // If there are not portals on screen,display "Nothing to show!"
        if (window.plugin.scoreboard.getPortals()) {
            html += window.plugin.scoreboard.portalTable();
        } else {
            html = '

Nothing to show!

';
        };

        if(window.useAndroidPanes()) {
            $('
' + html + '
').appendTo(document.body);
        } else {
            dialog({
                html: '
' + html + '
',
                dialogClass: 'ui-dialog-scoreboard',
                title: 'Scoreboard',
                id: 'Scoreboard',
                width: 700
            });
        }
    }

    //---- function that gets all visible enlightened links on screen
    window.plugin.scoreboard.getEnlLinks = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.enlL=0;
        // now every link that starts/ends at a point on screen
        $.each(window.links, function(guid, link) {
            // only consider links that start/end on-screen
            var points = link.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1])) {
                if (link.options.team === TEAM_ENL) {
                    window.plugin.scoreboard.enlL++;
                }
            }
        });
        return window.plugin.scoreboard.enlL;
    }

    //----function that gets all visible resistance links on screen
    window.plugin.scoreboard.getResLinks = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.resL=0;
        // now every link that starts/ends at a point on screen
        $.each(window.links, function(guid, link) {
            // only consider links that start/end on-screen
            var points = link.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1])) {// boroume na kanoume ta 2 if ena
                if (link.options.team === TEAM_RES) {
                    window.plugin.scoreboard.resL++;
                }
            }
        });
        return window.plugin.scoreboard.resL;
    }

    //----function that gets all visible enlightened fields on screen
    window.plugin.scoreboard.getEnlFields = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.enlF=0;
        // and now all fields that have a vertex on screen
        $.each(window.fields, function(guid, field) {
            // only consider fields with at least one vertex on screen
            var points = field.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1]) || displayBounds.contains(points[2])) {
                if (field.options.team === TEAM_ENL) {
                    window.plugin.scoreboard.enlF++;
                }
            }
        });
        return window.plugin.scoreboard.enlF;
    }

    //----function that gets all visible resistance fields on screen
    window.plugin.scoreboard.getResFields = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.resF=0;
        // and now all fields that have a vertex on screen
        $.each(window.fields, function(guid, field) {
            // only consider fields with at least one vertex on screen
            var points = field.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1]) || displayBounds.contains(points[2])) {
                if (field.options.team === TEAM_RES) {
                    window.plugin.scoreboard.resF++;
                }
            }
        });
        return window.plugin.scoreboard.resF;
    }

	// A function that creates the html code for the scoreboard table
	window.plugin.scoreboard.portalTable = function() {

        // html variable declaration
        var html = "";
		// Create the header
        html += '
'
        + '
'
        + 'Metrics	'
        + 'Enlightened	'
        + 'Resistance	'
        + '
\n';

		// if blocks to avoid division by zero
        if(window.plugin.scoreboard.enlP!=0){
            var avgEnl = window.plugin.scoreboard.enlPorLevels/window.plugin.scoreboard.enlP;
                avgEnl = avgEnl.toFixed(1);
            var avgHealthEnl = window.plugin.scoreboard.healthEnl/window.plugin.scoreboard.enlP;
                avgHealthEnl = avgHealthEnl.toFixed(1) }
        else{
        var avgEnl = '-';
        var avgHealthEnl = '0';
            }

        if(window.plugin.scoreboard.resP!=0){
            var avgRes = window.plugin.scoreboard.resPorLevels/window.plugin.scoreboard.resP;
                avgRes = avgRes.toFixed(1);
            var avgHealthRes = window.plugin.scoreboard.healthRes/window.plugin.scoreboard.resP;
                avgHealthRes =  avgHealthRes.toFixed(1);
        }
        else{
        var avgRes = '-';
        var avgHealthRes = '0';
            }

        // Get field-link count and assign them to variables
        var enlCountOfLinks= window.plugin.scoreboard.getEnlLinks();
        var resCountOfLinks= window.plugin.scoreboard.getResLinks();
        var enlCountOfFields= window.plugin.scoreboard.getEnlFields();
        var resCountOfFields= window.plugin.scoreboard.getResFields();

		// Creation of the html code
        html += '
Number of Portals	'+''
        +window.plugin.scoreboard.enlP+'	'+''+window.plugin.scoreboard.resP+'
'
        +'
Average Portal Level	'+''
        +avgEnl+'	'+''+avgRes+'
'
        +'
Number of Level 8 Portals	'+''
        +window.plugin.scoreboard.enlEightLevelP+'	'+''+window.plugin.scoreboard.resEightLevelP+'
'
        +'
Max Portal Level	'+''
        +window.plugin.scoreboard.maxEnl+'	'+''+window.plugin.scoreboard.maxRes+'
'
        +'
Number of Links	'+''
        +enlCountOfLinks+'	'+''+resCountOfLinks+'
'
        +'
Number of Fields	'+''
        +enlCountOfFields+'	'+''+resCountOfFields+'
'
        +'
Average portal Health	'+''
        +avgHealthEnl+'%	'+''+avgHealthRes+'%
';

        html += '
';

        html += '
Zoom in for a more accurate scoreboard!
';

        return html;
    }

    var setup =  function() {
        if(window.useAndroidPanes()) {  // use android panes,texture and style
            android.addPane("plugin-Scoreboard", "Scoreboard", "ic_action_paste");
            addHook("paneChanged", window.plugin.scoreboard.onPaneChanged);
        } else {
            $('#toolbox').append(' Scoreboard');
        }

        $('head').append('');
    }

    // PLUGIN END //////////////////////////////////////////////////////////

    setup.info = plugin_info; //add the script info data to the function as a property
    if(!window.bootPlugins) window.bootPlugins = [];
    window.bootPlugins.push(setup);
    // if IITC has already booted, immediately run the 'setup' function
    if(window.iitcLoaded && typeof setup === 'function') setup();
} // wrapper end
// inject code into site context
var script = document.createElement('script');
var info = {};
if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description };
script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');'));
(document.body || document.head || document.documentElement).appendChild(script);
    <commit_msg>made some more formation changes<commit_after>// ==UserScript==
// @id             iitc-plugin-dynamic-scoreboard@Costaspap
// @name           IITC plugin: Create a local scoreboard
// @category       Info
// @version        0.1.0.20140524.214738
// @namespace      https://github.com/jonatkins/ingress-intel-total-conversion
// @updateURL      https://secure.jonatkins.com/iitc/release/plugins/dynamic-scoreboard.meta.js
// @downloadURL    https://secure.jonatkins.com/iitc/release/plugins/dynamic-scoreboard.user.js
// @description    Display a scoreboard about all visible portals with statistics about both teams,like average portal level,link & field counts etc.
// @include        https://www.ingress.com/intel*
// @include        http://www.ingress.com/intel*
// @match          https://www.ingress.com/intel*
// @match          http://www.ingress.com/intel*
// @grant          none
// ==/UserScript==

// A plug in by Costaspap and harisbitsakou
function wrapper(plugin_info) {
    // ensure plugin framework is there, even if iitc is not yet loaded
    if(typeof window.plugin !== 'function') window.plugin = function() {};

    //PLUGIN AUTHORS: writing a plugin outside of the IITC build environment? if so, delete these lines!!
    //(leaving them in place might break the 'About IITC' page or break update checks)
    plugin_info.buildName = 'jonatkins';
    plugin_info.dateTimeVersion = '20140524.214738';
    plugin_info.pluginId = 'dynamic-scoreboard';
    //END PLUGIN AUTHORS NOTE

    // PLUGIN START //

    // use own namespace for plugin
    window.plugin.scoreboard = function() {};

    //gets data of all the visible portals on the screen
    window.plugin.scoreboard.getPortals = function() {

        var retval=false;

        var displayBounds = map.getBounds();

        window.plugin.scoreboard.enlP = 0;
        window.plugin.scoreboard.resP = 0;
        window.plugin.scoreboard.enlEightLevelP = 0;
        window.plugin.scoreboard.resEightLevelP = 0;
        window.plugin.scoreboard.enlPorLevels = 0;
        window.plugin.scoreboard.resPorLevels = 0;
        window.plugin.scoreboard.maxEnl=0;
        window.plugin.scoreboard.maxRes=0;
        window.plugin.scoreboard.healthEnl = 0;
        window.plugin.scoreboard.healthRes = 0;

         //get all portals on screen
        $.each(window.portals, function(i, portal) {
            // eliminate offscreen portals (selected, and in padding)
            if(!displayBounds.contains(portal.getLatLng())) return true;
            //if there are any portals return true
            retval=true;

			//variable that contains portal data
            var d = portal.options.data;

			//variable that contains each portal's team value
            var teamN = portal.options.team;

            switch (teamN) {
                case TEAM_RES:  //if the portal is captured by the resistance,increase each counter's value for resistance counters
                    window.plugin.scoreboard.healthRes += d.health;
                    window.plugin.scoreboard.resP++;
                    window.plugin.scoreboard.resPorLevels = window.plugin.scoreboard.resPorLevels + portal.options.level;
                    if(portal.options.level===8){window.plugin.scoreboard.resEightLevelP++;}
                    if(portal.options.level>window.plugin.scoreboard.maxRes){window.plugin.scoreboard.maxRes = portal.options.level;}
                    break;
                case TEAM_ENL: //if the portal is captured by the enlightened,increase each counter's value for enlightened counters
                    window.plugin.scoreboard.healthEnl += d.health;
                    window.plugin.scoreboard.enlP++;
                    window.plugin.scoreboard.enlPorLevels = window.plugin.scoreboard.enlPorLevels + portal.options.level;
                    if(portal.options.level===8){window.plugin.scoreboard.enlEightLevelP++;}
                    if(portal.options.level>window.plugin.scoreboard.maxEnl){window.plugin.scoreboard.maxEnl = portal.options.level;}
                    break;
            }

        });

        return retval;
    }

	// The final function that displays the scoreboard by calling the portalTable function
    window.plugin.scoreboard.displayScoreboard = function() {
        var html = '';

        // If there are not portals on screen,display "Nothing to show!"
        if (window.plugin.scoreboard.getPortals()) {
            html += window.plugin.scoreboard.portalTable();
        } else {
            html = '

Nothing to show!

';
        };

        if(window.useAndroidPanes()) {
            $('
' + html + '
').appendTo(document.body);
        } else {
            dialog({
                html: '
' + html + '
',
                dialogClass: 'ui-dialog-scoreboard',
                title: 'Scoreboard',
                id: 'Scoreboard',
                width: 700
            });
        }
    }

    //---- function that gets all visible enlightened links on screen
    window.plugin.scoreboard.getEnlLinks = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.enlL=0;
        // now every link that starts/ends at a point on screen
        $.each(window.links, function(guid, link) {
            // only consider links that start/end on-screen
            var points = link.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1])) {
                if (link.options.team === TEAM_ENL) {
                    window.plugin.scoreboard.enlL++;
                }
            }
        });
        return window.plugin.scoreboard.enlL;
    }

    //----function that gets all visible resistance links on screen
    window.plugin.scoreboard.getResLinks = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.resL=0;
        // now every link that starts/ends at a point on screen
        $.each(window.links, function(guid, link) {
            // only consider links that start/end on-screen
            var points = link.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1])) {// boroume na kanoume ta 2 if ena
                if (link.options.team === TEAM_RES) {
                    window.plugin.scoreboard.resL++;
                }
            }
        });
        return window.plugin.scoreboard.resL;
    }

    //----function that gets all visible enlightened fields on screen
    window.plugin.scoreboard.getEnlFields = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.enlF=0;
        // and now all fields that have a vertex on screen
        $.each(window.fields, function(guid, field) {
            // only consider fields with at least one vertex on screen
            var points = field.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1]) || displayBounds.contains(points[2])) {
                if (field.options.team === TEAM_ENL) {
                    window.plugin.scoreboard.enlF++;
                }
            }
        });
        return window.plugin.scoreboard.enlF;
    }

    //----function that gets all visible resistance fields on screen
    window.plugin.scoreboard.getResFields = function() {
        var displayBounds = map.getBounds();
        window.plugin.scoreboard.resF=0;
        // and now all fields that have a vertex on screen
        $.each(window.fields, function(guid, field) {
            // only consider fields with at least one vertex on screen
            var points = field.getLatLngs();
            if (displayBounds.contains(points[0]) || displayBounds.contains(points[1]) || displayBounds.contains(points[2])) {
                if (field.options.team === TEAM_RES) {
                    window.plugin.scoreboard.resF++;
                }
            }
        });
        return window.plugin.scoreboard.resF;
    }

	// A function that creates the html code for the scoreboard table
	window.plugin.scoreboard.portalTable = function() {

        // html variable declaration
        var html = "";
		// Create the header
        html += '
'
        + '
'
        + 'Metrics	'
        + 'Enlightened	'
        + 'Resistance	'
        + '
\n';

		// if blocks to avoid division by zero
        if(window.plugin.scoreboard.enlP!=0){
            var avgEnl = window.plugin.scoreboard.enlPorLevels/window.plugin.scoreboard.enlP;
                avgEnl = avgEnl.toFixed(1);
            var avgHealthEnl = window.plugin.scoreboard.healthEnl/window.plugin.scoreboard.enlP;
                avgHealthEnl = avgHealthEnl.toFixed(1)
        } else{
        var avgEnl = '-';
        var avgHealthEnl = '0';
            }

        if(window.plugin.scoreboard.resP!=0){
            var avgRes = window.plugin.scoreboard.resPorLevels/window.plugin.scoreboard.resP;
                avgRes = avgRes.toFixed(1);
            var avgHealthRes = window.plugin.scoreboard.healthRes/window.plugin.scoreboard.resP;
                avgHealthRes =  avgHealthRes.toFixed(1);
        } else {
        var avgRes = '-';
        var avgHealthRes = '0';
            }

        // Get field-link count and assign them to variables
        var enlCountOfLinks= window.plugin.scoreboard.getEnlLinks();
        var resCountOfLinks= window.plugin.scoreboard.getResLinks();
        var enlCountOfFields= window.plugin.scoreboard.getEnlFields();
        var resCountOfFields= window.plugin.scoreboard.getResFields();

		// Creation of the html code
        html += '
Number of Portals	'+''
        +window.plugin.scoreboard.enlP+'	'+''+window.plugin.scoreboard.resP+'
'
        +'
Average Portal Level	'+''
        +avgEnl+'	'+''+avgRes+'
'
        +'
Number of Level 8 Portals	'+''
        +window.plugin.scoreboard.enlEightLevelP+'	'+''+window.plugin.scoreboard.resEightLevelP+'
'
        +'
Max Portal Level	'+''
        +window.plugin.scoreboard.maxEnl+'	'+''+window.plugin.scoreboard.maxRes+'
'
        +'
Number of Links	'+''
        +enlCountOfLinks+'	'+''+resCountOfLinks+'
'
        +'
Number of Fields	'+''
        +enlCountOfFields+'	'+''+resCountOfFields+'
'
        +'
Average portal Health	'+''
        +avgHealthEnl+'%	'+''+avgHealthRes+'%
';

        html += '
';

        html += '
Zoom in for a more accurate scoreboard!
';

        return html;
    }

    var setup =  function() {
        if(window.useAndroidPanes()) {  // use android panes,texture and style
            android.addPane("plugin-Scoreboard", "Scoreboard", "ic_action_paste");
            addHook("paneChanged", window.plugin.scoreboard.onPaneChanged);
        } else {
            $('#toolbox').append(' Scoreboard');
        }

        $('head').append('');
    }

    // PLUGIN END //////////////////////////////////////////////////////////

    setup.info = plugin_info; //add the script info data to the function as a property
    if(!window.bootPlugins) window.bootPlugins = [];
    window.bootPlugins.push(setup);
    // if IITC has already booted, immediately run the 'setup' function
    if(window.iitcLoaded && typeof setup === 'function') setup();
} // wrapper end
// inject code into site context
var script = document.createElement('script');
var info = {};
if (typeof GM_info !== 'undefined' && GM_info && GM_info.script) info.script = { version: GM_info.script.version, name: GM_info.script.name, description: GM_info.script.description };
script.appendChild(document.createTextNode('('+ wrapper +')('+JSON.stringify(info)+');'));
(document.body || document.head || document.documentElement).appendChild(script);
    <|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import createEventHandle from '../createEventHandle';
import useLayoutEffect from '../useLayoutEffect';
import useStable from '../useStable';

type Callback = null | ((any) => void);
type AddListener = (target: EventTarget, listener: null | ((any) => void)) => () => void;

/**
 * This can be used with any event type include custom events.
 *
 * const click = useEvent('click', options);
 * useEffect(() => {
 *   click.setListener(target, onClick);
 *   return () => click.clear();
 * }).
 */
export default function useEvent(
  event: string,
  options?: ?{
    capture?: boolean,
    passive?: boolean
  }
): AddListener {
  const targetListeners = useStable(() => new Map());

  const addListener = useStable(() => {
    const addEventListener = createEventHandle(event, options);
    return (target: EventTarget, callback: Callback) => {
      const removeTargetListener = targetListeners.get(target);
      if (removeTargetListener != null) {
        removeTargetListener();
      }
      if (callback == null) {
        targetListeners.delete(target);
      }
      const removeEventListener = addEventListener(target, callback);
      targetListeners.set(target, removeEventListener);
      return removeEventListener;
    };
  });

  useLayoutEffect(() => {
    return () => {
      targetListeners.forEach((removeListener) => {
        removeListener();
      });
      targetListeners.clear();
    };
  }, []);

  return addListener;
}
<commit_msg>Fix 'yarn lint' issue<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow
 */

import createEventHandle from '../createEventHandle';
import useLayoutEffect from '../useLayoutEffect';
import useStable from '../useStable';

type Callback = null | ((any) => void);
type AddListener = (target: EventTarget, listener: null | ((any) => void)) => () => void;

/**
 * This can be used with any event type include custom events.
 *
 * const click = useEvent('click', options);
 * useEffect(() => {
 *   click.setListener(target, onClick);
 *   return () => click.clear();
 * }).
 */
export default function useEvent(
  event: string,
  options?: ?{
    capture?: boolean,
    passive?: boolean
  }
): AddListener {
  const targetListeners = useStable(() => new Map());

  const addListener = useStable(() => {
    const addEventListener = createEventHandle(event, options);
    return (target: EventTarget, callback: Callback) => {
      const removeTargetListener = targetListeners.get(target);
      if (removeTargetListener != null) {
        removeTargetListener();
      }
      if (callback == null) {
        targetListeners.delete(target);
      }
      const removeEventListener = addEventListener(target, callback);
      targetListeners.set(target, removeEventListener);
      return removeEventListener;
    };
  });

  useLayoutEffect(() => {
    return () => {
      targetListeners.forEach((removeListener) => {
        removeListener();
      });
      targetListeners.clear();
    };
  }, [targetListeners]);

  return addListener;
}
<|endoftext|>


<commit_before>'use babel';

let ConfigView;
let _ = require('underscore-plus');

export default class Config {

  constructor(manager) {

    this.manager = manager;

    this.config = undefined;
    this.projectConfig = undefined;
    this.editors = [];
  }

  getContent(filePath, projectRoot) {

    let content = this.manager.helper.getFileContent(filePath, projectRoot);

    if (!content) {

      return;
    }

    try {

      content = JSON.parse(content);

    } catch (e) {

      atom.notifications.addInfo('Error parsing .tern-project. Please check if it is a valid JSON file.', {

        dismissable: true
      });
      return;
    }

    return content;
  }

  prepareLibs(configStub) {

    let libs = {};

    if (!this.config.libs) {

      this.config.libs = {};

    } else {

      let libsAsObject = {};
      for (let lib of this.config.libs) {

        libsAsObject[lib] = {

          _active: false
        };
      }

      this.config.libs = libsAsObject;
    }

    for (let lib of Object.keys(configStub.libs)) {

      if (!this.config.libs[lib]) {

        libs[lib] = {

          _active: false
        };

      } else {

        libs[lib] = {

          _active: true
        };
      }
    }

    for (let lib of Object.keys(this.config.libs)) {

      if (lib === 'ecma5' || lib === 'ecma6') {

        atom.notifications.addInfo('You are using a outdated .tern-project file. Please remove libs ecma5, ecma6 manually and restart the Server via Packages -> Atom Ternjs -> Restart server. Then configure the project via Packages -> Atom Ternjs -> Configure project.', {

          dismissable: true
        });
      }

      if (!libs[lib]) {

        libs[lib] = {

          _active: true
        };
      }
    }

    this.config.libs = libs;
  }

  prepareEcma(configStub) {

    let ecmaVersions = {};

    for (let lib of Object.keys(configStub.ecmaVersions)) {

      ecmaVersions[lib] = configStub.ecmaVersions[lib];
    }

    this.config.ecmaVersions = ecmaVersions;

    if (this.config.ecmaVersion) {

      for (let lib of Object.keys(this.config.ecmaVersions)) {

        if (lib === 'ecmaVersion' + this.config.ecmaVersion) {

          this.config.ecmaVersions[lib] = true;

        } else {

          this.config.ecmaVersions[lib] = false;
        }
      }
    }
  }

  preparePlugins(availablePlugins) {

    if (!this.config.plugins) {

      this.config.plugins = {};
    }

    for (const plugin of Object.keys(availablePlugins)) {

      if (this.config.plugins[plugin]) {

        this.config.plugins[plugin] = this.mergeConfigObjects(availablePlugins[plugin].options, this.config.plugins[plugin]);
        this.config.plugins[plugin]._active = true;

      } else {

        this.config.plugins[plugin] = availablePlugins[plugin].options;
        this.config.plugins[plugin]._active = false;
      }
    }
  }

  registerEvents() {

    let close = this.configView.getClose();
    let cancel = this.configView.getCancel();

    close.addEventListener('click', (e) => {

      this.updateConfig();
      this.hide();
      this.manager.helper.focusEditor();
    });

    cancel.addEventListener('click', (e) => {

      this.destroyEditors();
      this.hide();
      this.manager.helper.focusEditor();
    });
  }

  mergeConfigObjects(obj1, obj2) {

    return _.deepExtend({}, obj1, obj2);
  }

  hide() {

    if (!this.configPanel) {

      return;
    }

    this.configPanel.hide();
  }

  clear() {

    this.hide();
    this.destroyEditors();
    this.config = undefined;
    this.projectConfig = undefined;

    if (!this.configView) {

      return;
    }

    this.configView.removeContent();
  }

  gatherData() {

    const configDefault = this.getContent('../config/tern-config.json', false);
    const pluginsTern = this.getContent('../config/tern-plugins.json', false);

    if (!configDefault) {

      return;
    }

    this.projectConfig = this.getContent('/.tern-project', true);
    this.config = this.projectConfig || {};

    if (this.projectConfig) {

      this.prepareEcma(configDefault);
      this.prepareLibs(configDefault);
      this.preparePlugins(pluginsTern);

      this.config = this.mergeConfigObjects(configDefault, this.config);

    } else {

      this.config = configDefault;
    }

    return true;
  }

  removeEditor(editor) {

    if (!editor) {

      return;
    }

    let idx = this.editors.indexOf(editor);

    if (idx === -1) {

      return;
    }

    this.editors.splice(idx, 1);
  }

  destroyEditors() {

    for (let editor of this.editors) {

      let buffer = editor.getModel().getBuffer();
      buffer.destroy();
    }

    this.editors = [];
  }

  updateConfig() {

    this.config.loadEagerly = [];
    this.config.dontLoad = [];

    for (let editor of this.editors) {

      let buffer = editor.getModel().getBuffer();
      let text = buffer.getText().trim();

      if (text === '') {

        continue;
      }

      this.config[editor.__ternjs_section].push(text);
    }

    this.destroyEditors();

    let newConfig = this.buildNewConfig();
    let newConfigJSON = JSON.stringify(newConfig, null, 2);

    this.manager.helper.updateTernFile(newConfigJSON, true);
  }

  buildNewConfig() {

    let newConfig = {};

    for (let key of Object.keys(this.config.ecmaVersions)) {

      if (this.config.ecmaVersions[key]) {

        newConfig.ecmaVersion = Number(key[key.length - 1]);
        break;
      }
    }

    if (!_.isEmpty(this.config.libs)) {

      newConfig.libs = [];

      for (let key of Object.keys(this.config.libs)) {

        if (this.config.libs[key]._active) {

          newConfig.libs.push(key);
        }
      }
    }

    if (this.config.loadEagerly.length !== 0) {

      newConfig.loadEagerly = this.config.loadEagerly;
    }

    if (this.config.dontLoad.length !== 0) {

      newConfig.dontLoad = this.config.dontLoad;
    }

    if (!_.isEmpty(this.config.plugins)) {

      newConfig.plugins = {};

      for (const key of Object.keys(this.config.plugins)) {

        if (this.config.plugins[key]._active) {

          delete this.config.plugins[key]._active;
          newConfig.plugins[key] = this.config.plugins[key];
        }
      }
    }

    return newConfig;
  }

  initConfigView() {

    if (!ConfigView) {

      ConfigView = require('./atom-ternjs-config-view');
    }

    this.configView = new ConfigView();
    this.configView.initialize(this);

    this.configPanel = atom.workspace.addRightPanel({

      item: this.configView,
      priority: 0
    });
    this.configPanel.hide();

    this.registerEvents();
  }

  show() {

    if (!this.configView) {

      this.initConfigView();
    }

    this.clear();

    atom.views.getView(this.configPanel).classList.add('atom-ternjs-config-panel');

    if (!this.gatherData()) {

      atom.notifications.addInfo('There is no active project. Please re-open or focus at least one JavaScript file of the project to configure.', {

        dismissable: true
      });
      return;
    }

    this.configView.buildOptionsMarkup(this.manager);
    this.configPanel.show();
  }

  destroy() {

    if (this.configView) {

      this.configView.destroy();
    }
    this.configView = undefined;

    if (this.configPanel) {

      this.configPanel.destroy();
    }
    this.configPanel = undefined;
  }
}
<commit_msg>remove no project message since it makes no sense at all<commit_after>'use babel';

let ConfigView;
let _ = require('underscore-plus');

export default class Config {

  constructor(manager) {

    this.manager = manager;

    this.config = undefined;
    this.projectConfig = undefined;
    this.editors = [];
  }

  getContent(filePath, projectRoot) {

    let content = this.manager.helper.getFileContent(filePath, projectRoot);

    if (!content) {

      return;
    }

    try {

      content = JSON.parse(content);

    } catch (e) {

      atom.notifications.addInfo('Error parsing .tern-project. Please check if it is a valid JSON file.', {

        dismissable: true
      });
      return;
    }

    return content;
  }

  prepareLibs(configStub) {

    let libs = {};

    if (!this.config.libs) {

      this.config.libs = {};

    } else {

      let libsAsObject = {};
      for (let lib of this.config.libs) {

        libsAsObject[lib] = {

          _active: false
        };
      }

      this.config.libs = libsAsObject;
    }

    for (let lib of Object.keys(configStub.libs)) {

      if (!this.config.libs[lib]) {

        libs[lib] = {

          _active: false
        };

      } else {

        libs[lib] = {

          _active: true
        };
      }
    }

    for (let lib of Object.keys(this.config.libs)) {

      if (lib === 'ecma5' || lib === 'ecma6') {

        atom.notifications.addInfo('You are using a outdated .tern-project file. Please remove libs ecma5, ecma6 manually and restart the Server via Packages -> Atom Ternjs -> Restart server. Then configure the project via Packages -> Atom Ternjs -> Configure project.', {

          dismissable: true
        });
      }

      if (!libs[lib]) {

        libs[lib] = {

          _active: true
        };
      }
    }

    this.config.libs = libs;
  }

  prepareEcma(configStub) {

    let ecmaVersions = {};

    for (let lib of Object.keys(configStub.ecmaVersions)) {

      ecmaVersions[lib] = configStub.ecmaVersions[lib];
    }

    this.config.ecmaVersions = ecmaVersions;

    if (this.config.ecmaVersion) {

      for (let lib of Object.keys(this.config.ecmaVersions)) {

        if (lib === 'ecmaVersion' + this.config.ecmaVersion) {

          this.config.ecmaVersions[lib] = true;

        } else {

          this.config.ecmaVersions[lib] = false;
        }
      }
    }
  }

  preparePlugins(availablePlugins) {

    if (!this.config.plugins) {

      this.config.plugins = {};
    }

    for (const plugin of Object.keys(availablePlugins)) {

      if (this.config.plugins[plugin]) {

        this.config.plugins[plugin] = this.mergeConfigObjects(availablePlugins[plugin].options, this.config.plugins[plugin]);
        this.config.plugins[plugin]._active = true;

      } else {

        this.config.plugins[plugin] = availablePlugins[plugin].options;
        this.config.plugins[plugin]._active = false;
      }
    }
  }

  registerEvents() {

    let close = this.configView.getClose();
    let cancel = this.configView.getCancel();

    close.addEventListener('click', (e) => {

      this.updateConfig();
      this.hide();
      this.manager.helper.focusEditor();
    });

    cancel.addEventListener('click', (e) => {

      this.destroyEditors();
      this.hide();
      this.manager.helper.focusEditor();
    });
  }

  mergeConfigObjects(obj1, obj2) {

    return _.deepExtend({}, obj1, obj2);
  }

  hide() {

    if (!this.configPanel) {

      return;
    }

    this.configPanel.hide();
  }

  clear() {

    this.hide();
    this.destroyEditors();
    this.config = undefined;
    this.projectConfig = undefined;

    if (!this.configView) {

      return;
    }

    this.configView.removeContent();
  }

  gatherData() {

    const configDefault = this.getContent('../config/tern-config.json', false);
    const pluginsTern = this.getContent('../config/tern-plugins.json', false);

    if (!configDefault) {

      console.error('Could not load: tern-config.json');
      return;
    }

    this.projectConfig = this.getContent('/.tern-project', true);
    this.config = this.projectConfig || {};

    if (this.projectConfig) {

      this.prepareEcma(configDefault);
      this.prepareLibs(configDefault);
      this.preparePlugins(pluginsTern);

      this.config = this.mergeConfigObjects(configDefault, this.config);

    } else {

      this.config = configDefault;
    }

    return true;
  }

  removeEditor(editor) {

    if (!editor) {

      return;
    }

    let idx = this.editors.indexOf(editor);

    if (idx === -1) {

      return;
    }

    this.editors.splice(idx, 1);
  }

  destroyEditors() {

    for (let editor of this.editors) {

      let buffer = editor.getModel().getBuffer();
      buffer.destroy();
    }

    this.editors = [];
  }

  updateConfig() {

    this.config.loadEagerly = [];
    this.config.dontLoad = [];

    for (let editor of this.editors) {

      let buffer = editor.getModel().getBuffer();
      let text = buffer.getText().trim();

      if (text === '') {

        continue;
      }

      this.config[editor.__ternjs_section].push(text);
    }

    this.destroyEditors();

    let newConfig = this.buildNewConfig();
    let newConfigJSON = JSON.stringify(newConfig, null, 2);

    this.manager.helper.updateTernFile(newConfigJSON, true);
  }

  buildNewConfig() {

    let newConfig = {};

    for (let key of Object.keys(this.config.ecmaVersions)) {

      if (this.config.ecmaVersions[key]) {

        newConfig.ecmaVersion = Number(key[key.length - 1]);
        break;
      }
    }

    if (!_.isEmpty(this.config.libs)) {

      newConfig.libs = [];

      for (let key of Object.keys(this.config.libs)) {

        if (this.config.libs[key]._active) {

          newConfig.libs.push(key);
        }
      }
    }

    if (this.config.loadEagerly.length !== 0) {

      newConfig.loadEagerly = this.config.loadEagerly;
    }

    if (this.config.dontLoad.length !== 0) {

      newConfig.dontLoad = this.config.dontLoad;
    }

    if (!_.isEmpty(this.config.plugins)) {

      newConfig.plugins = {};

      for (const key of Object.keys(this.config.plugins)) {

        if (this.config.plugins[key]._active) {

          delete this.config.plugins[key]._active;
          newConfig.plugins[key] = this.config.plugins[key];
        }
      }
    }

    return newConfig;
  }

  initConfigView() {

    if (!ConfigView) {

      ConfigView = require('./atom-ternjs-config-view');
    }

    this.configView = new ConfigView();
    this.configView.initialize(this);

    this.configPanel = atom.workspace.addRightPanel({

      item: this.configView,
      priority: 0
    });
    this.configPanel.hide();

    this.registerEvents();
  }

  show() {

    if (!this.configView) {

      this.initConfigView();
    }

    this.clear();

    if (!this.gatherData()) {

      return;
    }

    atom.views.getView(this.configPanel).classList.add('atom-ternjs-config-panel');

    this.configView.buildOptionsMarkup(this.manager);
    this.configPanel.show();
  }

  destroy() {

    if (this.configView) {

      this.configView.destroy();
    }
    this.configView = undefined;

    if (this.configPanel) {

      this.configPanel.destroy();
    }
    this.configPanel = undefined;
  }
}
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import { ModalPortal, ModalBackground, ModalDialog } from 'react-modal-dialog'
import { inject, observer } from 'mobx-react'
import AppStyles from '../Theme/AppStyles'
import Colors from '../Theme/Colors'
import { shell } from 'electron'

const ESCAPE_KEYSTROKE = 'Esc'
const ESCAPE_HINT = 'Cancel'
const ENTER_KEYSTROKE = 'Enter'
const ENTER_HINT = 'Send'
const DIALOG_TITLE = 'Custom Command'

const INPUT_PLACEHOLDER = ''
const FIELD_LABEL = 'command'

const Styles = {
  dialog: {
    borderRadius: 4,
    padding: 4,
    width: 450,
    backgroundColor: Colors.background,
    color: Colors.foreground
  },
  examples: {},
  example: {
    padding: 0,
    margin: '0 0 0 40px',
    color: Colors.bold
  },
  container: {
    ...AppStyles.Layout.vbox
  },
  keystrokes: {
    ...AppStyles.Layout.hbox,
    alignSelf: 'center',
    paddingTop: 10,
    paddingBottom: 20,
    fontSize: 13
  },
  hotkey: {
    padding: '0 10px'
  },
  keystroke: {
    backgroundColor: Colors.backgroundHighlight,
    color: Colors.foreground,
    padding: '4px 8px',
    borderRadius: 4
  },
  header: {
    ...AppStyles.Layout.vbox,
    padding: '1em 2em 0em'
  },
  body: {
    ...AppStyles.Layout.vbox,
    padding: '1em 2em 4em'
  },
  moreInfo: {
    paddingTop: '1em',
    fontSize: 12,
    color: Colors.foreground
  },
  title: {
    margin: 0,
    padding: 0,
    textAlign: 'left',
    fontWeight: 'normal',
    fontSize: 24,
    color: Colors.heading
  },
  subtitle: {
    color: Colors.foreground,
    textAlign: 'left',
    padding: 0,
    margin: 0
  },
  fieldLabel: {
    color: Colors.heading,
    fontSize: 13,
    textTransform: 'uppercase'
  },
  textField: {
    borderTop: 0,
    borderLeft: 0,
    borderRight: 0,
    borderBottom: `1px solid ${Colors.line}`,
    fontSize: 23,
    color: Colors.foregroundLight,
    lineHeight: '40px',
    backgroundColor: 'inherit'
  },
  link: {
    textDecoration: 'none',
    color: 'white',
    cursor: 'pointer'
  }
}

const INSTRUCTIONS =
Sends a custom command to your app.

@inject('session')
@observer
class SendCustomDialog extends Component {
  handleChange = e => {
    const { session } = this.props
    session.ui.setCustomMessage(e.target.value)
  }

  componentDidUpdate () {
    const field = ReactDOM.findDOMNode(this.field)

    field && field.focus()
  }

  onMoreInfo = e => {
    shell.openExternal(
      'https://github.com/infinitered/reactotron/blob/master/docs/tips.md#custom-commands'
    )
    e.preventDefault()
  }

  render () {
    const { ui } = this.props.session
    if (!ui.showSendCustomDialog) return null

    return (
      <ModalPortal>
        <ModalBackground onClose={ui.closeSendCustomDialog}>
          <ModalDialog style={Styles.dialog}>

{DIALOG_TITLE}

{INSTRUCTIONS}

                {FIELD_LABEL}
                <input
                  placeholder={INPUT_PLACEHOLDER}
                  style={Styles.textField}
                  type='text'
                  ref={node => (this.field = node)}
                  value={ui.customMessage}
                  onKeyPress={this.handleKeyPress}
                  onChange={this.handleChange}
                />

                  See{' '}

                    this tip
                  {' '}
                  for creating your own middleware.

                  {ESCAPE_KEYSTROKE} {ESCAPE_HINT}

                  {ENTER_KEYSTROKE} {ENTER_HINT}

          </ModalDialog>
        </ModalBackground>
      </ModalPortal>
    )
  }
}

export default SendCustomDialog
<commit_msg>Fix this dialog<commit_after>import React, { Component } from 'react'
import ReactDOM from 'react-dom'
import Modal from 'react-modal'
import { inject, observer } from 'mobx-react'
import AppStyles from '../Theme/AppStyles'
import Colors from '../Theme/Colors'
import { shell } from 'electron'

const ESCAPE_KEYSTROKE = 'Esc'
const ESCAPE_HINT = 'Cancel'
const ENTER_KEYSTROKE = 'Enter'
const ENTER_HINT = 'Send'
const DIALOG_TITLE = 'Custom Command'

const INPUT_PLACEHOLDER = ''
const FIELD_LABEL = 'command'

const Styles = {
  dialog: {
    borderRadius: 4,
    padding: 4,
    backgroundColor: Colors.background,
    color: Colors.foreground
  },
  examples: {},
  example: {
    padding: 0,
    margin: '0 0 0 40px',
    color: Colors.bold
  },
  container: {
    ...AppStyles.Layout.vbox
  },
  keystrokes: {
    ...AppStyles.Layout.hbox,
    alignSelf: 'center',
    paddingTop: 10,
    paddingBottom: 20,
    fontSize: 13
  },
  hotkey: {
    padding: '0 10px'
  },
  keystroke: {
    backgroundColor: Colors.backgroundHighlight,
    color: Colors.foreground,
    padding: '4px 8px',
    borderRadius: 4
  },
  header: {
    ...AppStyles.Layout.vbox,
    padding: '1em 2em 0em'
  },
  body: {
    ...AppStyles.Layout.vbox,
    padding: '1em 2em 4em'
  },
  moreInfo: {
    paddingTop: '1em',
    fontSize: 12,
    color: Colors.foreground
  },
  title: {
    margin: 0,
    padding: 0,
    textAlign: 'left',
    fontWeight: 'normal',
    fontSize: 24,
    color: Colors.heading
  },
  subtitle: {
    color: Colors.foreground,
    textAlign: 'left',
    padding: 0,
    margin: 0
  },
  fieldLabel: {
    color: Colors.heading,
    fontSize: 13,
    textTransform: 'uppercase'
  },
  textField: {
    borderTop: 0,
    borderLeft: 0,
    borderRight: 0,
    borderBottom: `1px solid ${Colors.line}`,
    fontSize: 23,
    color: Colors.foregroundLight,
    lineHeight: '40px',
    backgroundColor: 'inherit'
  },
  link: {
    textDecoration: 'none',
    color: 'white',
    cursor: 'pointer'
  }
}

const INSTRUCTIONS =
Sends a custom command to your app.

@inject('session')
@observer
class SendCustomDialog extends Component {
  handleChange = e => {
    const { session } = this.props
    session.ui.setCustomMessage(e.target.value)
  }

  componentDidUpdate() {
    const field = ReactDOM.findDOMNode(this.field)

    field && field.focus()
  }

  onMoreInfo = e => {
    shell.openExternal(
      'https://github.com/infinitered/reactotron/blob/master/docs/tips.md#custom-commands'
    )
    e.preventDefault()
  }

  render() {
    const { ui } = this.props.session
    if (!ui.showSendCustomDialog) return null

    return (
      <Modal
        isOpen
        onRequestClose={ui.closeSendCustomDialog}
        style={{ content: Styles.dialog, overlay: { zIndex: 5 } }}
      >

{DIALOG_TITLE}

{INSTRUCTIONS}

            {FIELD_LABEL}
            <input
              placeholder={INPUT_PLACEHOLDER}
              style={Styles.textField}
              type='text'
              ref={node => (this.field = node)}
              value={ui.customMessage}
              onKeyPress={this.handleKeyPress}
              onChange={this.handleChange}
            />

              See{' '}

                this tip
                  {' '}
              for creating your own middleware.

              {ESCAPE_KEYSTROKE} {ESCAPE_HINT}

              {ENTER_KEYSTROKE} {ENTER_HINT}

      </Modal>
    )
  }
}

export default SendCustomDialog
<|endoftext|>