<commit_before>const {HTMLElement} = window
const evaluate = require('evaluate-string')

module.exports = class MnInput extends HTMLElement {
  constructor(self) {
    self = super(self)
    return self
  }

  connectedCallback() {
    this.innerHTML = ''
    this.trimValue = true
    this._setStyle()
    this._setInput()
    this.setChangeEvents()
    this._setPlaceholder()
    this._setAttributeValue()
    this._setAttributeName()
    this._setAttributeDisabled()
    this._setAttributeReadonly()
    this._setAttributeMaxlength()
    this._setAttributeAutocapitalize()
    this._setAttributeAutocomplete()
    this._setAttributeSpellcheck()
    this._setAttributeAutofocus()
    this._setValidations()
  }

  static get observedAttributes() {
    return [
      'value',
      'name',
      'placeholder',
      'disabled',
      'readonly',
      'maxlength',
      'autocapitalize',
      'autofocus',
    ]
  }

  attributeChangedCallback(name, old, value) {
    this[name] = value
  }

  _setStyle() {
    this.classList.add('mn-input')
  }

  _setInput() {
    this.input = document.createElement('input')
    this.input.classList.add('input')

    this.appendChild(this.input)

    this.input.addEventListener('input', () => {
      this.hasAttribute('value')
        ? this.classList.add('has-value')
        : this.classList.remove('has-value')
    })

    this.input.addEventListener('change', () => { // set class .has-value
      if (this.trimValue) {
        this.input.value = this.input.value.replace(/\s{2,}/g, ' ').trim()
      }

      this.dispatchChangeEvent()

      this.hasAttribute('value')
        ? this.classList.add('has-value')
        : this.classList.remove('has-value')
    })

    this.input.addEventListener('blur', () => {
      this.hasAttribute('value')
        ? this.classList.add('has-value')
        : this.classList.remove('has-value')
    })

    const validate = () => { // validate
      const closestForm = this.closest('form') || this.closest('mn-form')
      closestForm && closestForm.classList.contains('submitted')
        ? this.validate()
        : null
    }

    this.input.addEventListener('keyup', validate)
    this.input.addEventListener('change', validate)
    this.input.addEventListener('input', validate)

    this.input.addEventListener('focus', () => {
      if (!this.hasAttribute('readonly') && !this.hasAttribute('disabled')) {
        this.classList.add('focus')
      }
    })

    this.input.addEventListener('blur', () => this.classList.remove('focus'))
  }

  setChangeEvents() {
    this.input.addEventListener('input', this.dispatchChangeEvent)
    this.input.addEventListener('blur', this.dispatchChangeEvent)
  }

  dispatchChangeEvent() {
    this.dispatchEvent(new Event('change'))
  }

  _setPlaceholder() {
    this.label = document.createElement('label')
    this.label.classList.add('placeholder')
    this.appendChild(this.label)
    this.placeholder = this.getAttribute('placeholder')
  }

  _setAttributeValue() {
    this.value = evaluate(this.getAttribute('value') || '')
    this.default = this.value
  }

  _setAttributeName() {
    const name = this.getAttribute('name')
    if (name) {
      this.name = name
    }
  }

  _setAttributeDisabled() {
    this.disabled = this.hasAttribute('disabled')
  }

  _setAttributeReadonly() {
    this.readonly = this.hasAttribute('readonly')
  }

  _setAttributeMaxlength() {
    this.maxlength = this.getAttribute('maxlength')
  }

  _setAttributeAutocapitalize() {
    this.autocapitalize = this.getAttribute('autocapitalize') || 'off'
  }

  _setAttributeAutocomplete() {
    this.input.setAttribute('autocomplete', 'off')
  }

  _setAttributeSpellcheck() {
    this.input.setAttribute('spellcheck', 'off')
  }

  _setAttributeAutofocus() {
    this.autofocus = this.hasAttribute('autofocus')
  }

  _setValidations() {
    this.validations = {
      required: () => this.value === '',
      pattern: () => {
        const reg = new RegExp(this.getAttribute('pattern'))

        return this.value
          ? !reg.test(this.value)
          : false
      },
    }
  }

  get value() {
    return this.input.value
  }

  set value(value = '') {
    if (this.input) {
      const differentValue = this.input.value !== value

      if (differentValue) {
        this.input.value = this.trimValue && value
          ? value.replace(/\s{2,}/g, ' ').trim()
          : value
        this.input.dispatchEvent(new Event('change'))
      }
    }
  }

  set name(value) {
    const form = this.closest('form') || this.closest('mn-form')
    const name = this.getAttribute('name')
    const element = this

    if (form && !form[name]) {
      Object.defineProperty(form, name, {
        get: () => {
          return element.getAttribute('name')
            ? element
            : undefined
        },
      })
    }
  }

  set placeholder(value) {
    if (this.label) {
      this.label.textContent = value
    }
  }

  set disabled(value) {
    if (this.input) {
      this.input.disabled = value || this.hasAttribute('disabled')
    }
  }

  set readonly(value) {
    this.input.readOnly = value || this.hasAttribute('readonly')
  }

  set maxlength(value) {
    if (this.input) {
      value
        ? this.input.setAttribute('maxlength', value)
        : this.input.removeAttribute('maxlength')
    }
  }

  set autocapitalize(value) {
    if (this.input) {
      value
        ? this.input.setAttribute('autocapitalize', value)
        : this.input.removeAttribute('autocapitalize')
    }
  }

  set autofocus(value) {
    if (this.input) {
      this.input.autofocus = value || this.hasAttribute('autofocus')
    }
  }

  blur() {
    this.input.blur()
  }

  focus() {
    // this.input.dispatchEvent(new Event('touchstart'))
    // this.input.dispatchEvent(new Event('touchsend'))
    this.input.focus()
  }

  validate() {
    const validations = {}

    for (const attribute of Object.keys(this.validations || {})) {
      const hasAttribute = this.hasAttribute(attribute)
      const attributeIsInvalid = this.validations[attribute]()

      if (hasAttribute && attributeIsInvalid) {
        this.classList.add(attribute)
        validations[attribute] = true
      } else {
        this.classList.remove(attribute)
      }
    }

    const isInvalid = Object.values(validations).some(item => item === true)

    isInvalid
      ? this.classList.add('invalid')
      : this.classList.remove('invalid')
  }
}
<commit_msg>fix has-value on blur<commit_after>const {HTMLElement} = window
const evaluate = require('evaluate-string')

module.exports = class MnInput extends HTMLElement {
  constructor(self) {
    self = super(self)
    return self
  }

  connectedCallback() {
    this.innerHTML = ''
    this.trimValue = true
    this._setStyle()
    this._setInput()
    this.setChangeEvents()
    this._setPlaceholder()
    this._setAttributeValue()
    this._setAttributeName()
    this._setAttributeDisabled()
    this._setAttributeReadonly()
    this._setAttributeMaxlength()
    this._setAttributeAutocapitalize()
    this._setAttributeAutocomplete()
    this._setAttributeSpellcheck()
    this._setAttributeAutofocus()
    this._setValidations()
  }

  static get observedAttributes() {
    return [
      'value',
      'name',
      'placeholder',
      'disabled',
      'readonly',
      'maxlength',
      'autocapitalize',
      'autofocus',
    ]
  }

  attributeChangedCallback(name, old, value) {
    this[name] = value
  }

  _setStyle() {
    this.classList.add('mn-input')
  }

  _setInput() {
    this.input = document.createElement('input')
    this.input.classList.add('input')

    this.appendChild(this.input)

    this.input.addEventListener('input', () => {
      this.hasAttribute('value')
        ? this.classList.add('has-value')
        : this.classList.remove('has-value')
    })

    this.input.addEventListener('change', () => { // set class .has-value
      if (this.trimValue) {
        this.input.value = this.input.value.replace(/\s{2,}/g, ' ').trim()
      }

      this.dispatchChangeEvent()

      this.hasAttribute('value')
        ? this.classList.add('has-value')
        : this.classList.remove('has-value')
    })

    this.input.addEventListener('blur', () => {
      this.hasAttribute('value') || this.input.value
        ? this.classList.add('has-value')
        : this.classList.remove('has-value')
    })

    const validate = () => { // validate
      const closestForm = this.closest('form') || this.closest('mn-form')
      closestForm && closestForm.classList.contains('submitted')
        ? this.validate()
        : null
    }

    this.input.addEventListener('keyup', validate)
    this.input.addEventListener('change', validate)
    this.input.addEventListener('input', validate)

    this.input.addEventListener('focus', () => {
      if (!this.hasAttribute('readonly') && !this.hasAttribute('disabled')) {
        this.classList.add('focus')
      }
    })

    this.input.addEventListener('blur', () => this.classList.remove('focus'))
  }

  setChangeEvents() {
    this.input.addEventListener('input', this.dispatchChangeEvent)
    this.input.addEventListener('blur', this.dispatchChangeEvent)
  }

  dispatchChangeEvent() {
    this.dispatchEvent(new Event('change'))
  }

  _setPlaceholder() {
    this.label = document.createElement('label')
    this.label.classList.add('placeholder')
    this.appendChild(this.label)
    this.placeholder = this.getAttribute('placeholder')
  }

  _setAttributeValue() {
    this.value = evaluate(this.getAttribute('value') || '')
    this.default = this.value
  }

  _setAttributeName() {
    const name = this.getAttribute('name')
    if (name) {
      this.name = name
    }
  }

  _setAttributeDisabled() {
    this.disabled = this.hasAttribute('disabled')
  }

  _setAttributeReadonly() {
    this.readonly = this.hasAttribute('readonly')
  }

  _setAttributeMaxlength() {
    this.maxlength = this.getAttribute('maxlength')
  }

  _setAttributeAutocapitalize() {
    this.autocapitalize = this.getAttribute('autocapitalize') || 'off'
  }

  _setAttributeAutocomplete() {
    this.input.setAttribute('autocomplete', 'off')
  }

  _setAttributeSpellcheck() {
    this.input.setAttribute('spellcheck', 'off')
  }

  _setAttributeAutofocus() {
    this.autofocus = this.hasAttribute('autofocus')
  }

  _setValidations() {
    this.validations = {
      required: () => this.value === '',
      pattern: () => {
        const reg = new RegExp(this.getAttribute('pattern'))

        return this.value
          ? !reg.test(this.value)
          : false
      },
    }
  }

  get value() {
    return this.input.value
  }

  set value(value = '') {
    if (this.input) {
      const differentValue = this.input.value !== value

      if (differentValue) {
        this.input.value = this.trimValue && value
          ? value.replace(/\s{2,}/g, ' ').trim()
          : value
        this.input.dispatchEvent(new Event('change'))
      }
    }
  }

  set name(value) {
    const form = this.closest('form') || this.closest('mn-form')
    const name = this.getAttribute('name')
    const element = this

    if (form && !form[name]) {
      Object.defineProperty(form, name, {
        get: () => {
          return element.getAttribute('name')
            ? element
            : undefined
        },
      })
    }
  }

  set placeholder(value) {
    if (this.label) {
      this.label.textContent = value
    }
  }

  set disabled(value) {
    if (this.input) {
      this.input.disabled = value || this.hasAttribute('disabled')
    }
  }

  set readonly(value) {
    this.input.readOnly = value || this.hasAttribute('readonly')
  }

  set maxlength(value) {
    if (this.input) {
      value
        ? this.input.setAttribute('maxlength', value)
        : this.input.removeAttribute('maxlength')
    }
  }

  set autocapitalize(value) {
    if (this.input) {
      value
        ? this.input.setAttribute('autocapitalize', value)
        : this.input.removeAttribute('autocapitalize')
    }
  }

  set autofocus(value) {
    if (this.input) {
      this.input.autofocus = value || this.hasAttribute('autofocus')
    }
  }

  blur() {
    this.input.blur()
  }

  focus() {
    // this.input.dispatchEvent(new Event('touchstart'))
    // this.input.dispatchEvent(new Event('touchsend'))
    this.input.focus()
  }

  validate() {
    const validations = {}

    for (const attribute of Object.keys(this.validations || {})) {
      const hasAttribute = this.hasAttribute(attribute)
      const attributeIsInvalid = this.validations[attribute]()

      if (hasAttribute && attributeIsInvalid) {
        this.classList.add(attribute)
        validations[attribute] = true
      } else {
        this.classList.remove(attribute)
      }
    }

    const isInvalid = Object.values(validations).some(item => item === true)

    isInvalid
      ? this.classList.add('invalid')
      : this.classList.remove('invalid')
  }
}
<|endoftext|>


<commit_before>// wait.js

(function($){

document.documentElement.className += ' wait';
var requestCount = 1;
var lastWait = 0;

function removeWait() {
	$(function() {
		setTimeout(function() {
			requestCount--;
			if (requestCount < 1) {
				var myWait = ++lastWait;
				setTimeout(function() {
					if (myWait == lastWait && requestCount < 1) {
						requestCount = 0;
						$(document.documentElement).removeClass("wait");
					}
				}, 400); // give browser a chance to draw the page
			}
		}, 0);
	});
}

$(removeWait);

$(window).bind("beforeunload unload", function() {
	requestCount++;
	$(document.documentElement).addClass("wait");
});

$(document).ajaxSend(function(event, xhr, options){
	requestCount++;
	$(document.documentElement).addClass("wait");
});
$(document).ajaxComplete(removeWait);

})(window.jQuery);

<commit_msg>Remove wait cursor after 1sec onbeforeunload if not unload<commit_after>// wait.js

(function($){

document.documentElement.className += ' wait';
var requestCount = 1;
var lastWait = 0;

function removeWait() {
	$(function() {
		setTimeout(function() {
			requestCount--;
			if (requestCount < 1) {
				var myWait = ++lastWait;
				setTimeout(function() {
					if (myWait == lastWait && requestCount < 1) {
						requestCount = 0;
						$(document.documentElement).removeClass("wait");
					}
				}, 400); // give browser a chance to draw the page
			}
		}, 0);
	});
}

$(removeWait);

$(window).bind("beforeunload", function() {
	requestCount++;
	$(document.documentElement).addClass("wait");
	setTimeout(removeWait, 1000);
});

$(window).bind("unload", function() {
	requestCount++;
	$(document.documentElement).addClass("wait");
});

$(document).ajaxSend(function(event, xhr, options){
	requestCount++;
	$(document.documentElement).addClass("wait");
});
$(document).ajaxComplete(removeWait);

})(window.jQuery);

<|endoftext|>


<commit_before>'use strict'

const {
  omit,
  recurseMap,
  fullRecurseMap,
  transtype,
  getWordsList,
} = require('../utilities')
const { throwError } = require('../errors')

const { availableInstructions } = require('./available')

// Process options after parsing
const processOpts = function ({ opts }) {
  const {
    // Positional arguments
    // eslint-disable-next-line id-length
    _: posArgs,
    ...optsA
  // Remove parser-specific values
  } = omit(opts, parserOpts)

  const { instruction, posArgs: posArgsA } = getInstruction({ posArgs })

  validatePosArgs({ posArgs: posArgsA })

  const optsB = transtypeValues({ opts: optsA })
  const optsC = parseArrays({ opts: optsB })

  return { instruction, opts: optsC }
}

const parserOpts = ['$0', 'help', 'version', 'instruction']

// When using default command, `config` will be the first argument
const getInstruction = function ({
  posArgs = [],
  posArgs: [instruction, ...posArgsA] = [],
}) {
  const validInstruction = availableInstructions
    .some(({ name }) => name === instruction)

  if (validInstruction) {
    return { instruction, posArgs: posArgsA }
  }

  return { instruction: 'run', posArgs }
}

const validatePosArgs = function ({ posArgs }) {
  if (posArgs.length === 0) { return }

  const posArgsA = getWordsList(posArgs, { quote: true })
  const message = `Unknown positional options: '${posArgsA}'`
  throwError(message, { reason: 'CONFIG_VALIDATION' })
}

// Allow JSON values for options
const transtypeValues = function ({ opts }) {
  return recurseMap(opts, transtype)
}

// `yargs` parses `--OPT.0` as an object `{ OPT: { 0: ... } }`
// We transform it to an array instead: `{ OPT: [...] }`
const parseArrays = function ({ opts }) {
  return fullRecurseMap(opts, parseArray)
}

const parseArray = function (value) {
  const isArray = value != null &&
    value.constructor === Object &&
    Object.keys(value).some(isIndex)
  if (!isArray) { return value }

  const arrA = Object.entries(value).filter(([index]) => isIndex(index))

  const indexes = arrA.map(([index]) => index)
  const length = Math.max(...indexes)
  const arrB = new Array(length).fill()

  const arrC = arrA.reduce(addArrayValue, arrB)
  return arrC
}

const isIndex = function (value) {
  return Number.isInteger(Number(value))
}

const addArrayValue = function (arr, [index, val]) {
  const indexA = Number(index)
  const start = arr.slice(0, indexA)
  const end = arr.slice(indexA + 1)
  return [...start, val, ...end]
}

module.exports = {
  processOpts,
}
<commit_msg>Improve CLI positional arguments check<commit_after>'use strict'

const { omit, recurseMap, fullRecurseMap, transtype } = require('../utilities')
const { throwPb } = require('../errors')

const { availableInstructions } = require('./available')

// Process options after parsing
const processOpts = function ({ opts }) {
  const {
    // Positional arguments
    // eslint-disable-next-line id-length
    _: posArgs,
    ...optsA
  // Remove parser-specific values
  } = omit(opts, parserOpts)

  const { instruction, posArgs: posArgsA } = getInstruction({ posArgs })

  validatePosArgs({ posArgs: posArgsA })

  const optsB = transtypeValues({ opts: optsA })
  const optsC = parseArrays({ opts: optsB })

  return { instruction, opts: optsC }
}

const parserOpts = ['$0', 'help', 'version', 'instruction']

// When using default command, `config` will be the first argument
const getInstruction = function ({
  posArgs = [],
  posArgs: [instruction, ...posArgsA] = [],
}) {
  const validInstruction = availableInstructions
    .some(({ name }) => name === instruction)

  if (validInstruction) {
    return { instruction, posArgs: posArgsA }
  }

  return { instruction: 'run', posArgs }
}

const validatePosArgs = function ({ posArgs }) {
  if (posArgs.length === 0) { return }

  const message = `Unknown positional options: '${posArgs.join(' ')}'`
  throwPb({ message, reason: 'CONFIG_VALIDATION', extra: { value: posArgs } })
}

// Allow JSON values for options
const transtypeValues = function ({ opts }) {
  return recurseMap(opts, transtype)
}

// `yargs` parses `--OPT.0` as an object `{ OPT: { 0: ... } }`
// We transform it to an array instead: `{ OPT: [...] }`
const parseArrays = function ({ opts }) {
  return fullRecurseMap(opts, parseArray)
}

const parseArray = function (value) {
  const isArray = value != null &&
    value.constructor === Object &&
    Object.keys(value).some(isIndex)
  if (!isArray) { return value }

  const arrA = Object.entries(value).filter(([index]) => isIndex(index))

  const indexes = arrA.map(([index]) => index)
  const length = Math.max(...indexes)
  const arrB = new Array(length).fill()

  const arrC = arrA.reduce(addArrayValue, arrB)
  return arrC
}

const isIndex = function (value) {
  return Number.isInteger(Number(value))
}

const addArrayValue = function (arr, [index, val]) {
  const indexA = Number(index)
  const start = arr.slice(0, indexA)
  const end = arr.slice(indexA + 1)
  return [...start, val, ...end]
}

module.exports = {
  processOpts,
}
<|endoftext|>


<commit_before>/* global describe, it, beforeEach */
const {expect} = require('chai')
  .use(require('chai-dom'))
  .use(require('chai-style'))
  // .use(require('chai-spies'))

let search // page object defined in method setPageObject
console.log(search)
let component

describe('mn-search (webcomponent)', () => {
  beforeEach(cleanView)
  beforeEach(createComponent)
  beforeEach(setPageObject)

  describe('instance', () => {
    it('should work with a constructor', () => {
      const MnSearch = window.customElements.get('mn-search')
      component = new MnSearch()
      expect(component).to.be.instanceof(MnSearch)
    })

    it('should work with document.createElement()', () => {
      const MnSearch = window.customElements.get('mn-search')
      component = document.createElement('mn-search')
      expect(component).to.be.instanceof(MnSearch)
    })
  })

  describe('component', () => {
    it('should have the .mn-search class', () => {
      expect(component).to.have.class('mn-search')
    })

    it('should contain a input property', () => {
      expect(component).to.have.property('input')
    })

    it('should contain a input child', () => {
      expect(component.querySelectorAll('input')).to.have.length(1)
    })

    it('should contain a menu property', () => {
      expect(component).to.have.property('menu')
    })

    it('should contain a menu child', () => {
      expect(component.querySelectorAll('menu')).to.have.length(1)
    })
  })

  describe('input', () => {
    it('should have autocomplete off by default', () => {
      expect(component.input).to.have.attribute('autocomplete', 'off')
    })

    it('should have spellcheck off by default', () => {
      expect(component.input).to.have.attribute('spellcheck', 'off')
    })
  })

  describe('property value', () => {
    it('should be undefined by default', () => {
      expect(component).to.have.value(undefined)
      expect(component.input).to.have.text('')
    })

    it('should be undefined when set a invalid value', () => {
      search.setProperty('value', 'teste')
      expect(component).to.have.value(undefined)
      expect(component.input).to.have.text('')
    })

    it('should be undefined when set a empty string', () => {
      search.setProperty('value', '')
      expect(component).to.have.value(undefined)
      expect(component.input).to.have.text('')
    })

    it('should be undefined when set undefined', () => {
      search.setProperty('value', undefined)
      expect(component).to.have.value(undefined)
      expect(component.input).to.have.text('')
    })

    // it('should be a string when set by option value', () => {
    //   search.setProperty('value', 'stark')

    //   expect(component).to.have.value('stark')
    //   expect(component.input).to.have.value('Stark')
    // })

    // it('should be a string when set by option text', () => {
    //   search.setProperty('value', 'Stark')
    //   expect(component).to.have.value('stark')
    //   expect(component.input).to.have.value('Stark')
    // })

    // it('should be a string when set by option text without value', () => {
    //   search.addOption('Baratheon')
    //   search.setProperty('value', 'Baratheon')
    //   expect(component).to.have.value('Baratheon')
    //   expect(component.input).to.have.value('Baratheon')
    // })

    // it('should keep value if enter and delete part of filter', () => {
    //   search.setProperty('value', 'Stark')
    //   search.writeText('St')
    //   expect(component).to.have.value('stark')
    //   expect(component.input).to.have.value('Stark')
    // })

    // it('should be undefined if enter and delete filter completely', () => {
    //   search.setProperty('value', 'Stark')
    //   search.writeText('')
    //   expect(component).to.have.value(undefined)
    //   expect(component.input).to.have.value('')
    // })

    // it('should evaluate to number when set option with numeric string value', () => {
    //   search.addOption('Test', '5')
    //   search.setProperty('value', 'Test')
    //   expect(component).to.have.value(5)
    //   expect(component.input).to.have.value('Test')
    // })

    // it('should evaluate to number when set option with numeric string text', () => {
    //   search.addOption('5')
    //   search.setProperty('value', '5')
    //   expect(component).to.have.value(5)
    //   expect(component.input).to.have.value('5')
    // })

    // it('should evaluate to number when set number instead string', () => {
    //   search.addOption('5')
    //   search.setProperty('value', 5)
    //   expect(component).to.have.value(5)
    //   expect(component.input).to.have.value('5')
    // })

    // it('should evaluate to boolean true', () => {
    //   search.addOption('Test', 'true')
    //   search.setProperty('value', 'Test')
    //   expect(component).to.have.value(true)
    //   expect(component.input).to.have.value('Test')
    // })

    // it('should evaluate to boolean false', () => {
    //   search.addOption('Test', 'false')
    //   search.setProperty('value', 'Test')
    //   expect(component).to.have.value(false)
    //   expect(component.input).to.have.value('Test')
    // })

    // it('should evaluate string object', () => {
    //   search.addOption('Test', '{name: \'targaryen\'}')
    //   search.setProperty('value', 'Test')
    //   expect(component.value).to.deep.equal({name: 'targaryen'})
    //   expect(component.input).to.have.value('Test')
    // })

    // it('should evaluate json object', () => {
    //   search.addOption('Test', '{"name": "targaryen"}')
    //   search.setProperty('value', 'Test')
    //   expect(component.value).to.deep.equal({name: 'targaryen'})
    //   expect(component.input).to.have.value('Test')
    // })

    // it('should evaluate array', () => {
    //   search.addOption('Test', '[1, "2"]')
    //   search.setProperty('value', 'Test')
    //   expect(component.value).to.deep.equal([1, '2'])
    //   expect(component.input).to.have.value('Test')
    // })
  })

  // describe('attribute value', () => {
  //   it('should set property value when attribute changed', () => {
  //     search.setAttribute('value', 'lannister')
  //     expect(component).to.have.value('lannister')
  //     expect(component.input).to.have.value('Lannister')
  //   })

  //   it('should set property value when attribute is removed', () => {
  //     search.setAttribute('value', 'Lannister')
  //     search.removeAttribute('value')
  //     expect(component).to.have.value(undefined)
  //     expect(component.input).to.have.value('')
  //   })
  // })

  // describe('attribute name', () => {
  //   it('should define a form getter if parent form exist and has an id', () => {
  //     search.setAttribute('name', 'test')
  //     const {formID} = window
  //     expect(formID.test).to.be.equal(component)
  //   })

  //   it('should define a form getter if parent form exist and has a name', () => {
  //     search.setAttribute('name', 'test')
  //     const {formName} = window
  //     expect(formName.test).to.be.equal(component)
  //   })

  //   it('should undefine form getter (name) if component name was removed', () => {
  //     search.setAttribute('name', 'test')
  //     search.removeAttribute('name')
  //     const {formName} = window
  //     expect(formName.test).to.be.undefined
  //   })

  //   it('should undefine form getter (id) if component name was removed', () => {
  //     search.setAttribute('name', 'test')
  //     search.removeAttribute('name')
  //     const {formID} = window
  //     expect(formID.test).to.be.undefined
  //   })

  //   it('should redefine form getter (name) if component name changed', () => {
  //     search.setAttribute('name', 'test')
  //     search.setAttribute('name', 'test2')
  //     const {formName} = window
  //     expect(formName.test2).to.be.equal(component)
  //   })

  //   it('should redefine form getter (id) if component name changed', () => {
  //     search.setAttribute('name', 'test')
  //     search.setAttribute('name', 'test2')
  //     const {formID} = window
  //     expect(formID.test2).to.be.equal(component)
  //   })
  // })

  // describe('property placeholder', () => {
  //   it('should set the placeholder text in label', () => {
  //     search.setProperty('placeholder', 'test')
  //     expect(component).to.contain('label').with.text('test')
  //   })

  //   it('should set the placeholder text in label', () => {
  //     search.setProperty('placeholder', 'test')
  //     search.setProperty('placeholder', 'test2')
  //     expect(component).to.contain('label').with.text('test2')
  //   })

  //   it('should set emtpy text if is undefined', () => {
  //     component.placeholder = undefined
  //     expect(component).to.contain('label').with.text('')
  //   })
  // })

  // describe('attribute placeholder', () => {
  //   it('should define a label as placeholder', () => {
  //     search.setAttribute('placeholder', 'test')
  //     expect(component).to.contain('label').with.text('test')
  //   })

  //   it('should change the text', () => {
  //     search.setAttribute('placeholder', 'test')
  //     search.setAttribute('placeholder', 'test2')
  //     expect(component).to.contain('label').with.text('test2')
  //   })

  //   it('should set empty text if is undefined', () => {
  //     expect(component).to.contain('label').with.text('')
  //   })

  //   it('should set empty text to label when attribute is removed', () => {
  //     search.setAttribute('placeholder', 'test')
  //     search.removeAttribute('placeholder')
  //     expect(component).to.contain('label').with.text('')
  //   })
  // })

  // describe('attribute readonly', () => {
  //   it('should define attribute in child input', () => {
  //     search.setAttribute('readonly')
  //     expect(component).to.contain('input').to.have.attribute('readonly')
  //   })

  //   it('should remove attribute from child input', () => {
  //     search.removeAttribute('readonly')
  //     expect(component).to.contain('input').not.have.attribute('readonly')
  //   })
  // })

  // describe('attribute disabled', () => {
  //   it('should define attribute in child input', () => {
  //     search.setAttribute('disabled')
  //     expect(component.input).to.have.attribute('disabled')
  //   })

  //   it('should remove attribute from child input', () => {
  //     search.removeAttribute('disabled')
  //     expect(component.input).to.not.have.attribute('disabled')
  //   })
  // })

  // describe('method validate()', () => {
  //   it('should be called on event change, if have a parent form.submitted', () => {
  //     component.closest('form').classList.add('submitted')
  //     const validate = spy.on(component, 'validate')
  //     component.input.dispatchEvent(new Event('change'))
  //     expect(validate).to.have.been.called()
  //   })

  //   it('should not called on event change, if not have a parent form.submitted', () => {
  //     const validate = spy.on(component, 'validate')
  //     component.input.dispatchEvent(new Event('change'))
  //     expect(validate).to.not.have.been.called()
  //   })

  //   it('should be called on event input, if have a parent form.submitted', () => {
  //     component.closest('form').classList.add('submitted')
  //     const validate = spy.on(component, 'validate')
  //     component.input.dispatchEvent(new Event('input'))
  //     expect(validate).to.have.been.called()
  //   })

  //   it('should not called on event input, if not have a parent form.submitted', () => {
  //     const validate = spy.on(component, 'validate')
  //     component.input.dispatchEvent(new Event('input'))
  //     expect(validate).to.not.have.been.called()
  //   })
  // })

  // describe('attribute required', () => {
  //   it('should be invalid if typed nothing', () => {
  //     search.setAttribute('required')
  //     component.validate()
  //     expect(component).to.have.class('invalid')
  //     expect(component).to.have.class('required')
  //   })

  //   it('should be valid if setted a valid value', () => {
  //     search.setAttribute('required')
  //     search.setProperty('value', 'Stark')
  //     component.validate()
  //     expect(component).to.not.have.class('invalid')
  //     expect(component).to.not.have.class('required')
  //   })

  //   it('should be valid if typed a valid value', () => {
  //     search.setAttribute('required')
  //     search.setProperty('value', 'Lannister')
  //     component.validate()
  //     expect(component).to.not.have.class('invalid')
  //     expect(component).to.not.have.class('required')
  //   })

  //   it('should validate if attribute was removed', () => {
  //     search.setAttribute('required')
  //     search.removeAttribute('required')
  //     component.validate()
  //     expect(component).to.not.have.class('invalid')
  //     expect(component).to.not.have.class('required')
  //   })
  // })
})

function cleanView() {
  const form = document.querySelector('form')

  if (form) {
    form.parentNode.removeChild(form)
  }
}

function createComponent() {
  const form = document.createElement('form')
  form.setAttribute('name', 'formName')
  form.setAttribute('id', 'formID')

  component = document.createElement('mn-search')

  form.appendChild(component)
  document.body.appendChild(form)
}

function setPageObject() {
  const PageObject = require('./search.po.js')
  search = new PageObject(component)
}
<commit_msg>reduce specs to mn-search, and start cover fetch<commit_after>/* global describe, it, beforeEach */
const {expect} = require('chai')
  .use(require('chai-dom'))
  .use(require('chai-style'))
  // .use(require('chai-spies'))

let search // page object defined in method setPageObject
console.log(search)
let component

describe('mn-search (webcomponent)', () => {
  beforeEach(cleanView)
  beforeEach(createComponent)
  beforeEach(setPageObject)

  describe('instance', () => {
    it('should work with a constructor', () => {
      const MnSearch = window.customElements.get('mn-search')
      component = new MnSearch()
      expect(component).to.be.instanceof(MnSearch)
    })

    it('should work with document.createElement()', () => {
      const MnSearch = window.customElements.get('mn-search')
      component = document.createElement('mn-search')
      expect(component).to.be.instanceof(MnSearch)
    })
  })

  describe('component', () => {
    it('should have the .mn-search class', () => {
      expect(component).to.have.class('mn-search')
    })

    it('should contain a input property', () => {
      expect(component).to.have.property('input')
    })

    it('should contain a input child', () => {
      expect(component.querySelectorAll('input')).to.have.length(1)
    })

    it('should contain a menu property', () => {
      expect(component).to.have.property('menu')
    })

    it('should contain a menu child', () => {
      expect(component.querySelectorAll('menu')).to.have.length(1)
    })
  })

  describe('input', () => {
    it('should have autocomplete off by default', () => {
      expect(component.input).to.have.attribute('autocomplete', 'off')
    })

    it('should have spellcheck off by default', () => {
      expect(component.input).to.have.attribute('spellcheck', 'off')
    })
  })

  describe('method fetch', () => {
    it('should be a function', () => {
      expect(component.fetch).to.be.a('function')
    })
  })
})

function cleanView() {
  const form = document.querySelector('form')

  if (form) {
    form.parentNode.removeChild(form)
  }
}

function createComponent() {
  const form = document.createElement('form')
  form.setAttribute('name', 'formName')
  form.setAttribute('id', 'formID')

  component = document.createElement('mn-search')

  form.appendChild(component)
  document.body.appendChild(form)
}

function setPageObject() {
  const PageObject = require('./search.po.js')
  search = new PageObject(component)
}
<|endoftext|>


<commit_before>/**
 * boot.js -- loads lively in any page that inserts throug a script tag
 *
 **/

/*
 #TODO refactor booting/loading/init of lively4
  - currently we have different entry points we should unify
 */

if (window.lively && window.lively4url) {
  console.log("CANCEL BOOT Lively4, because it is already loaded")
} else {

  console.group("BOOT")

  // for finding the baseURL...
  var script = document.currentScript
  var scriptURL = script.src;
  window.lively4url = scriptURL.replace("/src/client/boot.js","")

  var loadContainer = script.getAttribute("data-container") // some simple configuration
  console.log("lively4url: " + lively4url);

  // COPIED HERE BECAUSE resuse through libs does not work yet
  function loadJavaScriptThroughDOM(name, src, force) {
    return new Promise(function (resolve) {
      var scriptNode = document.querySelector(name);
      if (scriptNode) {
        scriptNode.remove();
      }
      var script = document.createElement("script");
      script.id = name;
      script.charset = "utf-8";
      script.type = "text/javascript";
      script.setAttribute("data-lively4-donotpersist","all");
      if (force) {
        src += +"?" + Date.now();
      }
      script.src = src;
      script.onload = function () {
        resolve();
      };
      document.head.appendChild(script);
    });
  }

  Promise.resolve().then( () => {
    return loadJavaScriptThroughDOM("systemjs", lively4url + "/src/external/systemjs/system.src.js");
  }).then(async () => {

    System.trace = true; // does not work in config

    SystemJS.config({
      // baseURL: lively4url + '/',
      babelOptions: {
        // stage2: false,
        // stage3: false,
        // es2015: false,
        // stage0: true,
        // stage1: true
        //presets: [
        //    ["es2015", { "loose": true, "modules": false }]
        //],
        plugins: []
      },
      meta: {
        '*.js': {
          babelOptions: {
          }
        },

        'workspace:*': {
          babelOptions: {
            es2015: false,
            stage2: false,
            stage3: false,
            plugins: ['babel-plugin-locals', 'babel-plugin-test', 'babel-plugin-doit-result']
          },
          loader: 'workspace-loader'
        }
      },
      map: {
        'plugin-babel': './src/external/babel/plugin-babel.js',
        'systemjs-plugin-babel': './src/external/babel/plugin-babel.js',
        'systemjs-babel-build': './src/external/babel/systemjs-babel-browser.js',
        'kernel': lively4url + '/src/client/legacy-kernel.js',
        'babel-plugin-locals': 'src/external/babel-plugin-locals.js',
        'babel-plugin-test': 'src/external/babel-plugin-test.js',
        'workspace-loader': './src/client/workspace-loader.js'
      },
      trace: true,
      transpiler: 'plugin-babel'
    })

    await System.import('babel-plugin-locals');

    SystemJS.config({
      meta: {
        '*.js': {
          babelOptions: {
            es2015: false,
            stage2: false,
            stage3: false,
            plugins: ['babel-plugin-locals']
          }
        }
      }
    });

    try {
      let { whenLoaded } = await System.import(lively4url + "/src/client/load.js")

      console.group("1/3: Wait for Service Worker...")
      await new Promise(whenLoaded);
      console.groupEnd();

      console.group("2/3: Look for uninitialized instances of Web Compoments");
      await lively.components.loadUnresolved();
      console.groupEnd();

      console.group("3/3: Initialize Document")
      await lively.initializeDocument(document, false, loadContainer);
      console.groupEnd();

      console.log("Finally loaded!");
      console.groupEnd(); // BOOT
    } catch(err) {
      console.log("Lively Loaging failed", err);
      alert("load Lively4 failed:" + err);
    }
  });
}
<commit_msg>AUTO-COMMIT src/client/boot.js<commit_after>/**
 * boot.js -- loads lively in any page that inserts throug a script tag
 *
 **/

/*
 #TODO refactor booting/loading/init of lively4
  - currently we have different entry points we should unify
 */

if (window.lively && window.lively4url) {
  console.log("CANCEL BOOT Lively4, because it is already loaded")
} else {

  console.group("BOOT")

  // for finding the baseURL...
  var script = document.currentScript
  var scriptURL = script.src;
  window.lively4url = scriptURL.replace("/src/client/boot.js","")

  var loadContainer = script.getAttribute("data-container") // some simple configuration
  console.log("lively4url: " + lively4url);

  // COPIED HERE BECAUSE resuse through libs does not work yet
  function loadJavaScriptThroughDOM(name, src, force) {
    return new Promise(function (resolve) {
      var scriptNode = document.querySelector(name);
      if (scriptNode) {
        scriptNode.remove();
      }
      var script = document.createElement("script");
      script.id = name;
      script.charset = "utf-8";
      script.type = "text/javascript";
      script.setAttribute("data-lively4-donotpersist","all");
      if (force) {
        src += +"?" + Date.now();
      }
      script.src = src;
      script.onload = function () {
        resolve();
      };
      document.head.appendChild(script);
    });
  }

  Promise.resolve().then( () => {
    return loadJavaScriptThroughDOM("systemjs", lively4url + "/src/external/systemjs/system.src.js");
  }).then(async () => {

    System.trace = true; // does not work in config

    SystemJS.config({
      // baseURL: lively4url + '/',
      babelOptions: {
        // stage2: false,
        // stage3: false,
        // es2015: false,
        // stage0: true,
        // stage1: true
        //presets: [
        //    ["es2015", { "loose": true, "modules": false }]
        //],
        plugins: []
      },
      meta: {
        '*.js': {
          babelOptions: {
          }
        },

        'workspace:*': {
          babelOptions: {
            es2015: false,
            stage2: false,
            stage3: false,
            plugins: ['babel-plugin-locals', 'babel-plugin-test', 'babel-plugin-doit-result']
          },
          loader: 'workspace-loader'
        }
      },
      map: {
        'plugin-babel': './src/external/babel/plugin-babel.js',
        'systemjs-plugin-babel': './src/external/babel/plugin-babel.js',
        'systemjs-babel-build': './src/external/babel/systemjs-babel-browser.js',
        'kernel': lively4url + '/src/client/legacy-kernel.js',
        'babel-plugin-doit-result': 'src/external/babel-plugin-doit-result.js',
        'babel-plugin-locals': 'src/external/babel-plugin-locals.js',
        'babel-plugin-test': 'src/external/babel-plugin-test.js',
        'workspace-loader': './src/client/workspace-loader.js'
      },
      trace: true,
      transpiler: 'plugin-babel'
    })

    await System.import('babel-plugin-locals');

    SystemJS.config({
      meta: {
        '*.js': {
          babelOptions: {
            es2015: false,
            stage2: false,
            stage3: false,
            plugins: ['babel-plugin-locals']
          }
        }
      }
    });

    try {
      let { whenLoaded } = await System.import(lively4url + "/src/client/load.js")

      console.group("1/3: Wait for Service Worker...")
      await new Promise(whenLoaded);
      console.groupEnd();

      console.group("2/3: Look for uninitialized instances of Web Compoments");
      await lively.components.loadUnresolved();
      console.groupEnd();

      console.group("3/3: Initialize Document")
      await lively.initializeDocument(document, false, loadContainer);
      console.groupEnd();

      console.log("Finally loaded!");
      console.groupEnd(); // BOOT
    } catch(err) {
      console.log("Lively Loaging failed", err);
      alert("load Lively4 failed:" + err);
    }
  });
}
<|endoftext|>


<commit_before>var path  = require('path'),
    _ = require('../../lib/util');

var regCommonjs = /require\(.*\)/,
    regEs6 = /import.*from/;

function extractMethod(options, file)
{
    var ret;

    if (regCommonjs.test(file.data))
    {
        ret = extractCommonjs(options, file);
    } else if (regEs6.test(file.data))
    {
        ret = extractEs6(options, file);
    } else
    {
        ret = extractGlobal(options.namespace, file);
    }

    return _.unique(ret);
}

var regModules = {
    _cache: {},
    get: function (namespace)
    {
        var ret;

        ret = this._cache[namespace];
        if (ret) return ret;

        ret = this._cache[namespace]
            = new RegExp('\\b' + namespace + '((\\.[\\$_\\w]+)|(\\[[\'"][\\$_\\w]+[\'"]\\]))', 'g');

        return ret;
    }
};

function extractGlobal(namespace, file)
{
    var modules = file.data.match(regModules.get(namespace));

    return modules ? _.map(modules, function (val)
    {
        val = val.substr(namespace.length);
        val = val[0] === '[' ? val.slice(2, -2) : val.slice(1);

        return val;
    }) : [];
}

function extractCommonjs(options, file)
{
    var requirePath = relativePath(file.path, options.output),
        regRequire = new RegExp('(\\w+)\\s*=\\s*require\\([\'"]' + requirePath + '(?:\\.js)?[\'"]\\)'),
        namespace = file.data.match(regRequire);

    if (namespace) namespace = namespace[1];

    return extractGlobal(namespace ? namespace : options.namespace, file);
}

function relativePath(from, to)
{
    var ret = path.relative(path.dirname(from), to)
                  .replace(/\\/g, '/')
                  .replace(/\.js$/, '')
                  .replace(/\./g, '\\.');

    if (!_.startWith(ret, '\\.')) ret = '\\./' + ret;

    return ret;
}

function extractEs6(options, file)
{
    var requirePath = relativePath(file.path, options.output),
        regImport = new RegExp('import\\s+(\\w+)\\s+from\\s*[\'"]' + requirePath + '[\'"]'),
        namespace = file.data.match(regImport);

    if (namespace)
    {
        namespace = namespace[1];
        return extractGlobal(namespace, file);
    }

    var regImportMembers = new RegExp('import\\s*\{([\\w,\\s]+)\}\\s*from\\s*[\'"]' + requirePath + '[\'"]'),
        methods = file.data.match(regImportMembers);

    if (methods) return methods[1].split(',');

    return extractGlobal(options.namespace, file);
}

function getFnPercentage(fnList, filesNum)
{
    var ret = {};

    _.each(fnList, function (fnName)
    {
        ret[fnName] = ret[fnName] !== undefined ? ret[fnName] + 1 : 1;
    });

    _.each(ret, function (val, key)
    {
        ret[key] = (val / filesNum * 100).toFixed(2) + '%';
    });

    return ret;
}

module.exports = function (options, cb)
{
    if (options.files.length === 0)
    {
        _.log('File list is empty, use include option only.');
        _.log({}, 'Modules found: {{#cyan}}' + JSON.stringify(options.include) + '{{/cyan}}');
        options.shareData.fnPercentage = {};
        return cb(null, options.include);
    }

    _.log('Scan source code: ');
    _.log.color(options.files.join('\n'), 'cyan');

    var files  = options.files,
        fnList = options.include,
        i, len;

    _.readPaths(files, options, function (err, files)
    {
        if (err) return cb(err);

        for (i = 0, len = files.length; i < len; i++)
        {
            var file = files[i];

            if (_.startWith(file.data, options.magicNum)) continue;

            file.data = _.stripCmts(file.data);

            fnList = fnList.concat(extractMethod(options, file));
        }

        fnList = _.map(fnList, function (fnName) { return _.trim(fnName) });

        options.shareData.fnPercentage = getFnPercentage(fnList, files.length);

        fnList = _.filter(_.unique(fnList), function (fnName)
        {
            return !_.contain(options.exclude, fnName);
        });

        _.log({}, 'Modules found: {{#cyan}}' + JSON.stringify(fnList) + '{{/cyan}}');

        cb(null, fnList);
    });
};
<commit_msg>Dev: Allow multiple module pattern<commit_after>var path  = require('path'),
    _ = require('../../lib/util');

var regCommonjs = /require\(.*\)/,
    regEs6 = /import.*from/;

function extractMethod(options, file)
{
    var ret = [];

    // Mixed use of commonjs and es6 module pattern is possible.
    if (regCommonjs.test(file.data)) ret = ret.concat(extractCommonjs(options, file));
    if (regEs6.test(file.data)) ret = ret.concat(extractEs6(options, file));
    ret = ret.concat(extractGlobal(options.namespace, file));

    return _.unique(ret);
}

var regModules = {
    _cache: {},
    get: function (namespace)
    {
        var ret;

        ret = this._cache[namespace];
        if (ret) return ret;

        ret = this._cache[namespace]
            = new RegExp('\\b' + namespace + '((\\.[\\$_\\w]+)|(\\[[\'"][\\$_\\w]+[\'"]\\]))', 'g');

        return ret;
    }
};

function extractGlobal(namespace, file)
{
    var modules = file.data.match(regModules.get(namespace));

    return modules ? _.map(modules, function (val)
    {
        val = val.substr(namespace.length);
        val = val[0] === '[' ? val.slice(2, -2) : val.slice(1);

        return val;
    }) : [];
}

function extractCommonjs(options, file)
{
    var requirePath = relativePath(file.path, options.output),
        regRequire = new RegExp('(\\w+)\\s*=\\s*require\\([\'"]' + requirePath + '(?:\\.js)?[\'"]\\)'),
        namespace = file.data.match(regRequire);

    if (namespace) namespace = namespace[1];

    return extractGlobal(namespace ? namespace : options.namespace, file);
}

function relativePath(from, to)
{
    var ret = path.relative(path.dirname(from), to)
                  .replace(/\\/g, '/')
                  .replace(/\.js$/, '')
                  .replace(/\./g, '\\.');

    if (!_.startWith(ret, '\\.')) ret = '\\./' + ret;

    return ret;
}

function extractEs6(options, file)
{
    var requirePath = relativePath(file.path, options.output),
        regImport = new RegExp('import\\s+(\\w+)\\s+from\\s*[\'"]' + requirePath + '[\'"]'),
        namespace = file.data.match(regImport);

    if (namespace)
    {
        namespace = namespace[1];
        return extractGlobal(namespace, file);
    }

    var regImportMembers = new RegExp('import\\s*\{([\\w,\\s]+)\}\\s*from\\s*[\'"]' + requirePath + '[\'"]'),
        methods = file.data.match(regImportMembers);

    if (methods) return methods[1].split(',');

    return extractGlobal(options.namespace, file);
}

function getFnPercentage(fnList, filesNum)
{
    var ret = {};

    _.each(fnList, function (fnName)
    {
        ret[fnName] = ret[fnName] !== undefined ? ret[fnName] + 1 : 1;
    });

    _.each(ret, function (val, key)
    {
        ret[key] = (val / filesNum * 100).toFixed(2) + '%';
    });

    return ret;
}

module.exports = function (options, cb)
{
    if (options.files.length === 0)
    {
        _.log('File list is empty, use include option only.');
        _.log({}, 'Modules found: {{#cyan}}' + JSON.stringify(options.include) + '{{/cyan}}');
        options.shareData.fnPercentage = {};
        return cb(null, options.include);
    }

    _.log('Scan source code: ');
    _.log.color(options.files.join('\n'), 'cyan');

    var files  = options.files,
        fnList = options.include,
        i, len;

    _.readPaths(files, options, function (err, files)
    {
        if (err) return cb(err);

        for (i = 0, len = files.length; i < len; i++)
        {
            var file = files[i];

            if (_.startWith(file.data, options.magicNum)) continue;

            file.data = _.stripCmts(file.data);

            fnList = fnList.concat(extractMethod(options, file));
        }

        fnList = _.map(fnList, function (fnName) { return _.trim(fnName) });

        options.shareData.fnPercentage = getFnPercentage(fnList, files.length);

        fnList = _.filter(_.unique(fnList), function (fnName)
        {
            return !_.contain(options.exclude, fnName);
        });

        _.log({}, 'Modules found: {{#cyan}}' + JSON.stringify(fnList) + '{{/cyan}}');

        cb(null, fnList);
    });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View, TouchableHighlight } from 'react-native';
import Collapsible from './Collapsible';
import { ViewPropTypes } from './config';

const COLLAPSIBLE_PROPS = Object.keys(Collapsible.propTypes);
const VIEW_PROPS = Object.keys(ViewPropTypes);

export default class Accordion extends Component {
  static propTypes = {
    sections: PropTypes.array.isRequired,
    renderHeader: PropTypes.func.isRequired,
    renderContent: PropTypes.func.isRequired,
    renderSectionTitle: PropTypes.func,
    onChange: PropTypes.func,
    align: PropTypes.oneOf(['top', 'center', 'bottom']),
    duration: PropTypes.number,
    easing: PropTypes.string,
    activeSections: PropTypes.arrayOf(PropTypes.number),
    underlayColor: PropTypes.string,
    touchableComponent: PropTypes.func,
    touchableProps: PropTypes.object,
    disabled: PropTypes.bool,
    expandFromBottom: PropTypes.bool,
    expandMultiple: PropTypes.bool,
    onAnimationEnd: PropTypes.func,
  };

  static defaultProps = {
    activeSections: [],
    underlayColor: 'black',
    disabled: false,
    expandFromBottom: false,
    expandMultiple: false,
    touchableComponent: TouchableHighlight,
    renderSectionTitle: () => null,
    onAnimationEnd: () => null,
  };

  constructor(props) {
    super(props);

    this.state = {
      activeSections: props.activeSections,
    };
  }

  componentDidUpdate(prevProps) {
    if (
      this.props.activeSections !== undefined &&
      this.props.activeSections !== prevProps.activeSections
    ) {
      this.setState({
        activeSections: this.props.activeSections,
      });
    }
  }

  _toggleSection(section) {
    if (!this.props.disabled) {
      let activeSections = [];

      if (this.state.activeSections.includes(section)) {
        activeSections = this.state.activeSections.filter(a => a !== section);
      } else if (this.props.expandMultiple) {
        activeSections = [...this.state.activeSections, section];
      } else {
        activeSections = [section];
      }

      if (this.props.activeSections === undefined) {
        this.setState({ activeSections });
      }

      if (this.props.onChange) {
        this.props.onChange(activeSections);
      }
    }
  }

  handleErrors = () => {
    if (!Array.isArray(this.props.sections)) {
      throw new Error('Sections should be an array');
    }
  };

  render() {
    let viewProps = {};
    let collapsibleProps = {};

    Object.keys(this.props).forEach(key => {
      if (COLLAPSIBLE_PROPS.indexOf(key) !== -1) {
        collapsibleProps[key] = this.props[key];
      } else if (VIEW_PROPS.indexOf(key) !== -1) {
        viewProps[key] = this.props[key];
      }
    });

    this.handleErrors();

    const Touchable = this.props.touchableComponent;
    const { activeSections } = this.state;

    const renderCollapsible = (section, key) => (
      <Collapsible
        collapsed={!activeSections.includes(key)}
        {...collapsibleProps}
        onAnimationEnd={() => this.props.onAnimationEnd(section, key)}
      >
        {this.props.renderContent(
          section,
          key,
          activeSections.includes(key),
          this.props.sections
        )}
      </Collapsible>
    );

    return (
      <View {...viewProps}>
        {this.props.sections.map((section, key) => (
          <View key={key}>
            {this.props.renderSectionTitle(
              section,
              key,
              activeSections.includes(key)
            )}

            {this.props.expandFromBottom && renderCollapsible(section, key)}

            <Touchable
              onPress={() => this._toggleSection(key)}
              underlayColor={this.props.underlayColor}
              {...this.props.touchableProps}
            >
              {this.props.renderHeader(
                section,
                key,
                activeSections.includes(key),
                this.props.sections
              )}
            </Touchable>

            {!this.props.expandFromBottom && renderCollapsible(section, key)}
          </View>
        ))}
      </View>
    );
  }
}
<commit_msg>refactor(Accordion): Remove state and use props for changes<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { View, TouchableHighlight } from 'react-native';
import Collapsible from './Collapsible';
import { ViewPropTypes } from './config';

const COLLAPSIBLE_PROPS = Object.keys(Collapsible.propTypes);
const VIEW_PROPS = Object.keys(ViewPropTypes);

export default class Accordion extends Component {
  static propTypes = {
    sections: PropTypes.array.isRequired,
    renderHeader: PropTypes.func.isRequired,
    renderContent: PropTypes.func.isRequired,
    renderSectionTitle: PropTypes.func,
    onChange: PropTypes.func,
    align: PropTypes.oneOf(['top', 'center', 'bottom']),
    duration: PropTypes.number,
    easing: PropTypes.string,
    activeSections: PropTypes.arrayOf(PropTypes.number),
    underlayColor: PropTypes.string,
    touchableComponent: PropTypes.func,
    touchableProps: PropTypes.object,
    disabled: PropTypes.bool,
    expandFromBottom: PropTypes.bool,
    expandMultiple: PropTypes.bool,
    onAnimationEnd: PropTypes.func,
  };

  static defaultProps = {
    activeSections: [],
    underlayColor: 'black',
    disabled: false,
    expandFromBottom: false,
    expandMultiple: false,
    touchableComponent: TouchableHighlight,
    renderSectionTitle: () => null,
    onAnimationEnd: () => null,
  };

  _toggleSection(section) {
    if (!this.props.disabled) {
      const { activeSections, expandMultiple, onChange } = this.props;

      let updatedSections = [];

      if (activeSections.includes(section)) {
        updatedSections = activeSections.filter(a => a !== section);
      } else if (expandMultiple) {
        updatedSections = [...activeSections, section];
      } else {
        updatedSections = [section];
      }

      onChange && onChange(updatedSections);
    }
  }

  handleErrors = () => {
    if (!Array.isArray(this.props.sections)) {
      throw new Error('Sections should be an array');
    }
  };

  render() {
    let viewProps = {};
    let collapsibleProps = {};

    Object.keys(this.props).forEach(key => {
      if (COLLAPSIBLE_PROPS.includes(key)) {
        collapsibleProps[key] = this.props[key];
      } else if (VIEW_PROPS.includes(key)) {
        viewProps[key] = this.props[key];
      }
    });

    this.handleErrors();

    const {
      activeSections,
      expandFromBottom,
      sections,
      underlayColor,
      touchableProps,
      touchableComponent: Touchable,
      onAnimationEnd,
      renderContent,
      renderHeader,
      renderSectionTitle,
    } = this.props;

    const renderCollapsible = (section, key) => (
      <Collapsible
        collapsed={!activeSections.includes(key)}
        {...collapsibleProps}
        onAnimationEnd={() => onAnimationEnd(section, key)}
      >
        {renderContent(section, key, activeSections.includes(key), sections)}
      </Collapsible>
    );

    return (
      <View {...viewProps}>
        {sections.map((section, key) => (
          <View key={key}>
            {renderSectionTitle(section, key, activeSections.includes(key))}

            {expandFromBottom && renderCollapsible(section, key)}

            <Touchable
              onPress={() => this._toggleSection(key)}
              underlayColor={underlayColor}
              {...touchableProps}
            >
              {renderHeader(
                section,
                key,
                activeSections.includes(key),
                sections
              )}
            </Touchable>

            {!expandFromBottom && renderCollapsible(section, key)}
          </View>
        ))}
      </View>
    );
  }
}
<|endoftext|>


<commit_before>// @flow
const p2 = require('p2')
const { vec2 } = p2
const PlayerInput = require('./PlayerInput.js')
const Ship = require('./Ship.js')
const C = require('./constants.js')

function resetBody (body) {
  delete body._listeners
  body.id = p2.Body._idCounter++
  body.world = null

  // no need to reset shapes / boundingRadius / AABB
  // no need to reset mass/invMass/inertia/invInertia/Solve
  // no need to reset fixedRotation, massMultipler

  vec2.set(body.position, 0, 0)
  vec2.set(body.interpolatedPosition, 0, 0)
  vec2.set(body.previousPosition, 0, 0)
  vec2.set(body.velocity, 0, 0)

  body.angle = body.previousAngle = body.interpolatedAngle = 0
  body.angularVelocity = 0

  // no need to reset damping/angularDamping

  body.setZeroForce()
  body.resetConstraintVelocity()

  body.idleTime = body.timeLastSleepy = 0
  body.concavePath = null
  body._wakeUpAfterNarrowphase = false
}

class Turn {
  ships: Array<?Ship>
  events: Array<?Array<GameEvent>>
  serverEvents: Array<Object>

  constructor (
    ships: Array<?Ship>,
    events: Array<?Array<GameEvent>>,
    serverEvents: Array<Object>
  ) {
    this.ships = ships
    this.events = events
    this.serverEvents = serverEvents
  }

  getFreeShipSlot () : number {
    let freeSlot = 0

    const reservedSlots = {}
    this.serverEvents.forEach(serverEvent => {
      if (serverEvent.type !== C.SERVER_EVENT.SPAWN_PLAYER) return
      reservedSlots[serverEvent.val] = true
    })

    while (this.ships[freeSlot] != null || reservedSlots[freeSlot]) ++freeSlot
    return freeSlot
  }

  addEvents (shipId: number, evs: Array<GameEvent>) : boolean {
    const existingEvents = this.events[shipId] || []
    this.events[shipId] = existingEvents

    // check if new events are meaningful, and save them if so.
    // let the caller know.
    let changed = false

    evs.forEach((ev) => {
      let foundRelated = false

      for (let i = existingEvents.length - 1; i >= 0; --i) {
        const exEv = existingEvents[i]

        if (exEv.type === ev.type) {
          foundRelated = true

          if (exEv.val !== ev.val) {
            changed = true
            existingEvents.push(ev)
          }

          break
        }
      }

      if (!foundRelated) {
        changed = true
        existingEvents.push(ev)
      }
    })

    return changed
  }

  addServerEvent (evs: GameEvent | Array<GameEvent>) : boolean {
    if (!Array.isArray(evs)) evs = [evs]
    this.serverEvents = this.serverEvents.concat(evs)

    // TO-DO: actually check if significant changes were made
    return true
  }

  evolve (map: Track, world: p2.World, bodies: Array<p2.Body>, dt: number) {
    const nextInputs = []

    // create / remove bodies
    const length = Math.max(this.ships.length, bodies.length)
    for (let i = 0; i < length; ++i) {
      const ship = this.ships[i]
      let body = bodies[i]

      if (ship) {
        if (body == null) {
          body = new p2.Body({
            mass: 5,
            position: [102, 52],
            angle: -Math.PI / 2,
            fixedRotation: true
          })

          const shape = new p2.Box({
            width: 2,
            height: 2,
            material: C.SHIP_MTRL
          })
          body.addShape(shape)
          bodies[i] = body
        } else {
          resetBody(body)
        }
        world.addBody(body)
      }
    }

    // consume server events
    this.serverEvents.forEach((sev) => {
      switch (sev.type) {
        case C.SERVER_EVENT.SPAWN_PLAYER:
          const shipId = sev.val

          const body = new p2.Body({
            mass: 5,
            position: [102, 52],
            angle: -Math.PI / 2,
            fixedRotation: true
          })
          bodies[shipId] = body

          const shape = new p2.Box({
            width: 2,
            height: 2,
            material: C.SHIP_MTRL
          })
          body.addShape(shape)
          world.addBody(body)

          const ship = new Ship({
            position: vec2.clone(body.position),
            velocity: vec2.clone(body.velocity),
            angle: body.angle,
            username: sev.username,
            color: sev.color,
            input: new PlayerInput(),
            checkpoint: 1000,
            lap: 0
          })
          this.ships[shipId] = ship

          break
      }
    })

    // apply player inputs
    this.ships.forEach((ship, i) => {
      if (ship == null) return

      let body = bodies[i]

      // init / reset props for determinism
      vec2.copy(body.position, ship.position)
      vec2.copy(body.velocity, ship.velocity)
      body.angle = ship.angle
      vec2.set(body.force, 0, 0)
      body.angularForce = 0

      const playerEvents = this.events[i] || []
      const input = new PlayerInput(ship.input)
      input.turnL = false
      input.turnR = false
      playerEvents.forEach(input.applyPlayerEvent, input)

      // turn left
      if (input.turnL) body.angle += -Math.PI / 2

      // turn right
      if (input.turnR) body.angle += Math.PI / 2

      // main thruster force
      let boost = 0
      if (input.gas) boost = input.boost ? 2 : 1
      body.applyForceLocal([0, -C.FORCE * boost])

      // leaning right by engaging left thruster
      if (input.leanR) body.applyForceLocal([C.FORCE, 0])

      // leaning left by engaging right thruster
      if (input.leanL) body.applyForceLocal([-C.FORCE, 0])

      // air drag
      vec2.scale(body.velocity, body.velocity, 0.99)

      nextInputs[i] = input
    })

    world.step(dt)

    const nextShips = bodies.map((body, i) => {
      const ship = this.ships[i]
      if (!ship) return

      const ci = Math.floor((body.position[1] + C.CELL_EDGE / 2) / C.CELL_EDGE)
      const cj = Math.floor((body.position[0] + C.CELL_EDGE / 2) / C.CELL_EDGE)

      const oldCheckpoint = ship.checkpoint
      const cell = map[ci][cj]
      let checkpoint = cell === ' ' ? NaN : Number(map[ci][cj])
      let lap = ship.lap

      if (Math.random() < 0.1) {
        console.log(`ci: ${ci}, cj: ${cj}, oldC: ${oldCheckpoint}, c: ${checkpoint}`)
      }

      if (isNaN(checkpoint)) checkpoint = oldCheckpoint
      else if (checkpoint !== oldCheckpoint) {
        console.log('checkpoint', checkpoint)
        if (checkpoint > oldCheckpoint + 1) lap++
      }

      return new Ship({
        position: vec2.clone(body.position),
        velocity: vec2.clone(body.velocity),
        angle: body.angle,
        username: ship.username,
        color: ship.color,
        input: nextInputs[i],
        checkpoint,
        lap
      })
    })

    const nextTurn = new Turn(nextShips, [], [])
    return nextTurn
  }
}

module.exports = Turn
<commit_msg>Fix lap/checkpoing logic<commit_after>// @flow
const p2 = require('p2')
const { vec2 } = p2
const PlayerInput = require('./PlayerInput.js')
const Ship = require('./Ship.js')
const C = require('./constants.js')

function resetBody (body) {
  delete body._listeners
  body.id = p2.Body._idCounter++
  body.world = null

  // no need to reset shapes / boundingRadius / AABB
  // no need to reset mass/invMass/inertia/invInertia/Solve
  // no need to reset fixedRotation, massMultipler

  vec2.set(body.position, 0, 0)
  vec2.set(body.interpolatedPosition, 0, 0)
  vec2.set(body.previousPosition, 0, 0)
  vec2.set(body.velocity, 0, 0)

  body.angle = body.previousAngle = body.interpolatedAngle = 0
  body.angularVelocity = 0

  // no need to reset damping/angularDamping

  body.setZeroForce()
  body.resetConstraintVelocity()

  body.idleTime = body.timeLastSleepy = 0
  body.concavePath = null
  body._wakeUpAfterNarrowphase = false
}

class Turn {
  ships: Array<?Ship>
  events: Array<?Array<GameEvent>>
  serverEvents: Array<Object>

  constructor (
    ships: Array<?Ship>,
    events: Array<?Array<GameEvent>>,
    serverEvents: Array<Object>
  ) {
    this.ships = ships
    this.events = events
    this.serverEvents = serverEvents
  }

  getFreeShipSlot () : number {
    let freeSlot = 0

    const reservedSlots = {}
    this.serverEvents.forEach(serverEvent => {
      if (serverEvent.type !== C.SERVER_EVENT.SPAWN_PLAYER) return
      reservedSlots[serverEvent.val] = true
    })

    while (this.ships[freeSlot] != null || reservedSlots[freeSlot]) ++freeSlot
    return freeSlot
  }

  addEvents (shipId: number, evs: Array<GameEvent>) : boolean {
    const existingEvents = this.events[shipId] || []
    this.events[shipId] = existingEvents

    // check if new events are meaningful, and save them if so.
    // let the caller know.
    let changed = false

    evs.forEach((ev) => {
      let foundRelated = false

      for (let i = existingEvents.length - 1; i >= 0; --i) {
        const exEv = existingEvents[i]

        if (exEv.type === ev.type) {
          foundRelated = true

          if (exEv.val !== ev.val) {
            changed = true
            existingEvents.push(ev)
          }

          break
        }
      }

      if (!foundRelated) {
        changed = true
        existingEvents.push(ev)
      }
    })

    return changed
  }

  addServerEvent (evs: GameEvent | Array<GameEvent>) : boolean {
    if (!Array.isArray(evs)) evs = [evs]
    this.serverEvents = this.serverEvents.concat(evs)

    // TO-DO: actually check if significant changes were made
    return true
  }

  evolve (map: Track, world: p2.World, bodies: Array<p2.Body>, dt: number) {
    const nextInputs = []

    // create / remove bodies
    const length = Math.max(this.ships.length, bodies.length)
    for (let i = 0; i < length; ++i) {
      const ship = this.ships[i]
      let body = bodies[i]

      if (ship) {
        if (body == null) {
          body = new p2.Body({
            mass: 5,
            position: [102, 52],
            angle: -Math.PI / 2,
            fixedRotation: true
          })

          const shape = new p2.Box({
            width: 2,
            height: 2,
            material: C.SHIP_MTRL
          })
          body.addShape(shape)
          bodies[i] = body
        } else {
          resetBody(body)
        }
        world.addBody(body)
      }
    }

    // consume server events
    this.serverEvents.forEach((sev) => {
      switch (sev.type) {
        case C.SERVER_EVENT.SPAWN_PLAYER:
          const shipId = sev.val

          const body = new p2.Body({
            mass: 5,
            position: [102, 52],
            angle: -Math.PI / 2,
            fixedRotation: true
          })
          bodies[shipId] = body

          const shape = new p2.Box({
            width: 2,
            height: 2,
            material: C.SHIP_MTRL
          })
          body.addShape(shape)
          world.addBody(body)

          const ship = new Ship({
            position: vec2.clone(body.position),
            velocity: vec2.clone(body.velocity),
            angle: body.angle,
            username: sev.username,
            color: sev.color,
            input: new PlayerInput(),
            checkpoint: 1,
            lap: 0
          })
          this.ships[shipId] = ship

          break
      }
    })

    // apply player inputs
    this.ships.forEach((ship, i) => {
      if (ship == null) return

      let body = bodies[i]

      // init / reset props for determinism
      vec2.copy(body.position, ship.position)
      vec2.copy(body.velocity, ship.velocity)
      body.angle = ship.angle
      vec2.set(body.force, 0, 0)
      body.angularForce = 0

      const playerEvents = this.events[i] || []
      const input = new PlayerInput(ship.input)
      input.turnL = false
      input.turnR = false
      playerEvents.forEach(input.applyPlayerEvent, input)

      // turn left
      if (input.turnL) body.angle += -Math.PI / 2

      // turn right
      if (input.turnR) body.angle += Math.PI / 2

      // main thruster force
      let boost = 0
      if (input.gas) boost = input.boost ? 2 : 1
      body.applyForceLocal([0, -C.FORCE * boost])

      // leaning right by engaging left thruster
      if (input.leanR) body.applyForceLocal([C.FORCE, 0])

      // leaning left by engaging right thruster
      if (input.leanL) body.applyForceLocal([-C.FORCE, 0])

      // air drag
      vec2.scale(body.velocity, body.velocity, 0.99)

      nextInputs[i] = input
    })

    world.step(dt)

    const nextShips = bodies.map((body, i) => {
      const ship = this.ships[i]
      if (!ship) return

      const ci = Math.floor((body.position[1] + C.CELL_EDGE / 2) / C.CELL_EDGE)
      const cj = Math.floor((body.position[0] + C.CELL_EDGE / 2) / C.CELL_EDGE)

      const oldCheckpoint = ship.checkpoint
      const cell = map[ci][cj]
      let lap = ship.lap

      // obtain current checkpoint
      let checkpoint = (cell === ' ' ? NaN : Number(map[ci][cj]))
      if (isNaN(checkpoint)) checkpoint = oldCheckpoint

      // detect checkpoint change
      // checkpoint number is descending, lap is indicated as a
      // jump from low number to high number
      if (checkpoint !== oldCheckpoint) {
        if (checkpoint == oldCheckpoint - 1) {
          // cool, progressing
        } else if (checkpoint == oldCheckpoint + 1) {
          // going backwards
        } else if (checkpoint > oldCheckpoint + 1) {
          // number jump indicates going from last checkpoint to
          // first checkpoint, i.e. crossed finish line
          lap++
        } else if (checkpoint < oldCheckpoint - 1) {
          // going backwards and crossed finish line
          lap--
        }
      }

      return new Ship({
        position: vec2.clone(body.position),
        velocity: vec2.clone(body.velocity),
        angle: body.angle,
        username: ship.username,
        color: ship.color,
        input: nextInputs[i],
        checkpoint,
        lap
      })
    })

    const nextTurn = new Turn(nextShips, [], [])
    return nextTurn
  }
}

module.exports = Turn
<|endoftext|>


<commit_before>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.03'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var incoming_ONG = 0;
var NinjaAutoClickStatus = 1;
var Time_to_ONG = 1800000;
var lootBoxes = ['boosts', 'ninj', 'cyb', 'hpt', 'bean', 'chron', 'badges', 'badgesav'];

//BB Options Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var refreshRate = 1000;
var RKAlertFrequency = 8;
var RKAutoClickStatus = 1;
var RKPlayAudio = 1;

//RK Variables
var start = -1;
var content = "empty";
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var len = 0;
var Logicat = 0;
var oldRKLocation = -1;
var oldRC = Molpy.redactedClicks - 1;
var oldLC = Molpy.Boosts['Logicat'].power - 1;
var RKLevel = '-1';
var RKLocation = '123';
var RKNew = 1;
var RKNewAudio = 1;
var RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function ToggleMenus(wantOpen) {
	for (i=0, len = lootBoxes.length; i < len; i++) {
		if (lootBoxes[i] == wantOpen) {
			if (Molpy.options.showhide[lootBoxes[i]] != 1) {
				showhideToggle(lootBoxes[i]);
			}
		}
		else {
			if (Molpy.options.showhide[lootBoxes[i]]) {
				showhideToggle(lootBoxes[i]);
			}
		}
	}
}

function FindRK() {
	/*
	RV of 1 is Sand Tools
	RV of 2 is Castle Tools
	RV of 3 is Boosts Main Page
	RV of 4 is Boosts Menus, Hill People Tech, etc.
	RV of 5 is Badges Earned
	RV of 6 is Badges Available
	*/

	//Determines RK location
	RKLocation = '123';
	Molpy.Notify('RK Group: ' + Molpy.redactedGr, 1);
	if (Molpy.redactedVisible > 3) {
		RKLocation = Molpy.redactedGr;
	}

	//Opens RK location
	ToggleMenus(RKLocation);

	//Resets old RK variables
	oldRKLocation = Molpy.redactedVisible;
	oldRC = Molpy.redactedClicks;
	oldLC = Molpy.Boosts['Logicat'].power;
}

function ManualRKClick() {

}

function RedundaKitty() {
	//Refresh Timer Variable
	RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

	//If a RedundaKitty is active
	if (Molpy.redactedVisible > 0) {

		//Checks if RK is new
		if (RKNew == 1 || Molpy.redactedVisible != oldRKLocation || Molpy.redactedClicks > oldRC || Molpy.Boosts['Logicat'].power != oldLC) {
			RKNewAudio = 1;
			RKNew = 0;
			//Finds RK if appropriate BeachBall option enabled
			if (RKAutoClickStatus > 0) {
				FindRK();
			}
		}

		//Determines if it is an RK or LC
		//If RK is visible
		if ($('#redacteditem').length) {
			$('#redacteditem').css("border","2px solid red"); //Highlights RK
			content = $('#redacteditem').html();
			//If RK contains word statement, it is a LC.
			if (content.indexOf("statement") !== -1) {
				//Molpy.Notify('Logicat Found', 1);
				Logicat = 1;
			}
			//Otherwise it is an RK
			else {
				Logicat = 0;
				start = content.indexOf("ClickRedacted");
				content = content.substring(start,start+17);
				content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
				len = content.length;
				RKLevel = content.substring(13,len);
				if (RKLevel != 0) {
					Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
				}
			}
		}
		//If RK not visible, LC to 99.
		else {
			Logicat = 99;
		}

		//Clicks RK if AutoClick Enabled
		if (RKAutoClickStatus == 2 && Logicat == 0 ) {
			Molpy.ClickRedacted(RKLevel);
			RKNew = 1;
			RKLocation = '123';
			ToggleMenus('123');
		}
		//Solves LC if AutoClick enabled
		else if (Logicat == 1 && LCAutoClickStatus == 1) {
			SolveLogicat();
			RKNew = 1;
			RKLocation = '123';
			ToggleMenus('123');
		}

		//Redundakitty Notifications for Manual Clicking (Title Bar, Audio)
		else {
			document.title = "! kitten !";
			//If RK Audio Alerts Enabled
			if (AudioAlertsStatus == 1 || AudioAlertsStatus == 3) {
				//If proper mNP and hasn't yet played this mNP
				if (Math.floor(RKTimer % RKAlertFrequency) == 0 && RKPlayAudio == 1) {
					audio_Bell.play();
					RKPlayAudio = 0;
				}
				else {
					RKPlayAudio = 1;
				}
			}
		}
	}
	//If no RK active, update title Timer. Reset some variables.
	else {
		document.title = RKTimer;
		oldRKLocation = -1;
		RKNew = 1;
		RKPlayAudio = 0;
	}
}

function SolveLogicat() {
	var i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 2) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
		case 'RefreshRate':
			refreshRate = parsseInt(prompt('Please enter your desired BeachBall refresh rate in milliseconds (500 - 3600):', 1000));
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error', 1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only'; RKPlayAudio = 1;}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG'; RKPlayAudio = 1;}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status, 1);}
	}
	else if (option == 'RKAutoClick') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'Find RK Only'; RKNew = 1;}
		else if (status == 2) {description = 'On'; RKNew = 1;}
		else {Molpy.Notify('Display Description Error - RKAutoClick: ' + status, 1);}
	}
	else if (option == 'RefreshRate') {
		description = refreshRate;
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
$('#optionsItems').append('

Refresh Rate

');
$('#optionsItems').append('

Spawn RK

');
//$('#optionsItems').append('

Blank

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);
DisplayDescription('RefreshRate', refreshRate);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1);
	setInterval(function() {
		Molpy.Notify('1 Refresh', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, refreshRate);
}

//Run Main Loop after 1 second startup delay
setTimeout(MainLoop, 1000);

function SpawnRK() {
	Molpy.redactedCountup = Molpy.redactedToggle - 1;
}

<commit_msg>Bug fixing<commit_after>//v1.0 as Starting Point
//v2.0 Cleaning up code. Setting up Menu Structure and Initial Settings.

var version = '2.0 Beta';
var SCBversion = '3.03'; //Last SandCastle Builder version tested

//Declare and Initialize Variables
var incoming_ONG = 0;
var NinjaAutoClickStatus = 1;
var Time_to_ONG = 1800000;
var lootBoxes = ['boosts', 'ninj', 'cyb', 'hpt', 'bean', 'chron', 'badges', 'badgesav'];

//BB Options Variables
var AudioAlertsStatus = 3;
var audio_Bell = new Audio("http://xenko.comxa.com/Ship_Bell.mp3");
	audio_Bell.volume = 1;
var audio_Chime = new Audio("http://xenko.comxa.com/Chime.mp3");
	audio_Chime.volume = 1;
var BorderAlertStatus = 1;
var description = "Error";
var refreshRate = 1000;
var RKAlertFrequency = 8;
var RKAutoClickStatus = 1;
var RKPlayAudio = 1;

//RK Variables
var start = -1;
var content = "empty";
var LCAutoClickStatus = 0;
var LCSolution = 'blank';
var len = 0;
var Logicat = 0;
var oldRKLocation = -1;
var oldRC = Molpy.redactedClicks - 1;
var oldLC = Molpy.Boosts['Logicat'].power - 1;
var RKLevel = '-1';
var RKLocation = '123';
var RKNew = 1;
var RKNewAudio = 1;
var RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

//Ninja AutoClicker and Border Warnings
function Ninja() {
    if (Molpy.ninjad == 0) {
        if (Molpy.npbONG == 0 && BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid red");
        }
        else {
            incoming_ONG = 0;
            if (NinjaAutoClickStatus == 1) {
                Molpy.ClickBeach();
				Molpy.Notify('Ninja Auto Click', 1);
				if (BorderAlertStatus == 1) {
					$("#beach").css("border","1px solid white");
				}
            }
            else if (BorderAlertStatus == 1) {
            $("#beach").css("border","4px solid green");
            }

        }
	}
    else if (Time_to_ONG <= 15000) {
		if (BorderAlertStatus == 1) {
			$("#beach").css("border","4px solid yellow");
		}
        if (incoming_ONG == 0 && (AudioAlertsStatus == 3 || AudioAlertsStatus == 4)) {
			audio_Chime.play();
			incoming_ONG = 1;
        }
    }
    else if (BorderAlertStatus == 1) {
        $("#beach").css("border","1px solid white");
	}
}

function ToggleMenus(wantOpen) {
	for (i=0, len = lootBoxes.length; i < len; i++) {
		if (lootBoxes[i] == wantOpen) {
			if (Molpy.options.showhide[lootBoxes[i]] != 1) {
				showhideToggle(lootBoxes[i]);
			}
		}
		else {
			if (Molpy.options.showhide[lootBoxes[i]]) {
				showhideToggle(lootBoxes[i]);
			}
		}
	}
}

function FindRK() {
	/*
	RV of 1 is Sand Tools
	RV of 2 is Castle Tools
	RV of 3 is Boosts Main Page
	RV of 4 is Boosts Menus, Hill People Tech, etc.
	RV of 5 is Badges Earned
	RV of 6 is Badges Available
	*/

	//Determines RK location
	RKLocation = '123';
	Molpy.Notify('RK Group: ' + Molpy.redactedGr, 1);
	if (Molpy.redactedVisible > 3) {
		RKLocation = Molpy.redactedGr;
	}

	//Opens RK location
	ToggleMenus(RKLocation);

	//Resets old RK variables
	oldRKLocation = Molpy.redactedVisible;
	oldRC = Molpy.redactedClicks;
	oldLC = Molpy.Boosts['Logicat'].power;
}

function ManualRKClick() {

}

function RedundaKitty() {
	//Refresh Timer Variable
	RKTimer = Molpy.redactedToggle - Molpy.redactedCountup;

	//If a RedundaKitty is active
	if (Molpy.redactedVisible > 0) {

		//Checks if RK is new
		if (RKNew == 1 || Molpy.redactedVisible != oldRKLocation || Molpy.redactedClicks > oldRC || Molpy.Boosts['Logicat'].power != oldLC) {
			RKNewAudio = 1;
			RKNew = 0;
			//Finds RK if appropriate BeachBall option enabled
			if (RKAutoClickStatus > 0) {
				FindRK();
			}
		}

		//Determines if it is an RK or LC
		//If RK is visible
		if ($('#redacteditem').length) {
			$('#redacteditem').css("border","2px solid red"); //Highlights RK
			content = $('#redacteditem').html();
			//If RK contains word statement, it is a LC.
			if (content.indexOf("statement") !== -1) {
				//Molpy.Notify('Logicat Found', 1);
				Logicat = 1;
			}
			//Otherwise it is an RK
			else {
				Logicat = 0;
				start = content.indexOf("ClickRedacted");
				content = content.substring(start,start+17);
				content = content.replace(/[&\/\\#,+()$~%.'":*?<>{}]/g,'');
				len = content.length;
				RKLevel = content.substring(13,len);
				if (RKLevel != 0) {
					Molpy.Notify('RedundaKitty Level is: ' + RKLevel, 1);
				}
			}
		}
		//If RK not visible, LC to 99.
		else {
			Logicat = 99;
		}

		//Clicks RK if AutoClick Enabled
		if (RKAutoClickStatus == 2 && Logicat == 0 ) {
			Molpy.ClickRedacted(RKLevel);
			RKNew = 1;
			RKLocation = '123';
			ToggleMenus('123');
		}
		//Solves LC if AutoClick enabled
		else if (Logicat == 1 && LCAutoClickStatus == 1) {
			SolveLogicat();
			RKNew = 1;
			RKLocation = '123';
			ToggleMenus('123');
		}

		//Redundakitty Notifications for Manual Clicking (Title Bar, Audio)
		else {
			document.title = "! kitten !";
			//If RK Audio Alerts Enabled
			if (AudioAlertsStatus == 1 || AudioAlertsStatus == 3) {
				//If proper mNP and hasn't yet played this mNP
				if (Math.floor(RKTimer % RKAlertFrequency) == 0 && RKPlayAudio == 1) {
					audio_Bell.play();
					RKPlayAudio = 0;
				}
				else {
					RKPlayAudio = 1;
				}
			}
		}
	}
	//If no RK active, update title Timer. Reset some variables.
	else {
		document.title = RKTimer;
		oldRKLocation = -1;
		RKNew = 1;
		RKPlayAudio = 0;
	}
}

function SolveLogicat() {
	var i = 65;
	do
		{LCSolution = String.fromCharCode(i);
		i++;}
	while (Molpy.redactedPuzzleTarget != Molpy.redactedSGen.StatementValue(LCSolution));
	Molpy.ClickRedactedPuzzle(LCSolution);
}

function SwitchOption(option) {
	switch (option) {
		case 'RKAutoClick':
			RKAutoClickStatus++;
			if (RKAutoClickStatus > 2) {RKAutoClickStatus = 0;}
			status = RKAutoClickStatus;
			break;
		case 'LCAutoClick':
			LCAutoClickStatus++;
			if (LCAutoClickStatus > 1) {LCAutoClickStatus = 0;}
			status = LCAutoClickStatus;
			break;
		case 'NinjaAutoClick':
			NinjaAutoClickStatus++;
			if (NinjaAutoClickStatus > 1) {NinjaAutoClickStatus = 0;}
			status = NinjaAutoClickStatus;
			break;
		case 'BorderAlert':
			BorderAlertStatus++;
			if (BorderAlertStatus > 1) {
				BorderAlertStatus = 0;
				$("#beach").css("border","1px solid white");
			}
			status = BorderAlertStatus;
			break;
		case 'AudioAlerts':
			AudioAlertsStatus++;
			if (AudioAlertsStatus > 3) {AudioAlertsStatus = 0;}
			status = AudioAlertsStatus;
			break;
		case 'RefreshRate':
			refreshRate = parseInt(prompt('Please enter your desired BeachBall refresh rate in milliseconds (500 - 3600):', 1000));
			break;
	}
	DisplayDescription(option, status);
}

function DisplayDescription(option, status) {
	error = 0;
	if (option == 'LCAutoClick' || option == 'NinjaAutoClick' || option == 'BorderAlert') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'On';}
		else {Molpy.Notify('Display Description Error', 1);}
	}
	else if (option == 'AudioAlerts') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'RK Only'; RKPlayAudio = 1;}
		else if (status == 2) {description = 'ONG Only';}
		else if (status == 3) {description = 'RK and ONG'; RKPlayAudio = 1;}
		else {Molpy.Notify('Display Description Error - Audio Alerts: ' + status, 1);}
	}
	else if (option == 'RKAutoClick') {
		if (status == 0) {description = 'Off';}
		else if (status == 1) {description = 'Find RK Only'; RKNew = 1;}
		else if (status == 2) {description = 'On'; RKNew = 1;}
		else {Molpy.Notify('Display Description Error - RKAutoClick: ' + status, 1);}
	}
	else if (option == 'RefreshRate') {
		description = refreshRate;
	}
	else {
		Molpy.Notify(option + ' is not a valid option', 1);
		error = 1;
	}

	if (error == 0) {g(option + 'Desc').innerHTML = '
' + description;}
}

//Beach Ball Startup
//Set Settings
if (Molpy.Got('Kitnip') == 1){RKAlertFrequency = 10;}

//Create Menu
$('#optionsItems').append('

BeachBall Settings

');
$('#optionsItems').append('

Redundakitty Auto Click

');
$('#optionsItems').append('

Logicat Auto Click

');
$('#optionsItems').append('

Ninja Auto Click

');
$('#optionsItems').append('

Ninja Visual Alert

');
$('#optionsItems').append('

Audio Alerts

');
$('#optionsItems').append('

Refresh Rate

');
$('#optionsItems').append('

Spawn RK

');
//$('#optionsItems').append('

Blank

');
DisplayDescription('RKAutoClick', RKAutoClickStatus);
DisplayDescription('LCAutoClick', LCAutoClickStatus);
DisplayDescription('NinjaAutoClick', NinjaAutoClickStatus);
DisplayDescription('BorderAlert', BorderAlertStatus);
DisplayDescription('AudioAlerts', AudioAlertsStatus);
DisplayDescription('RefreshRate', refreshRate);

function MainLoop() {
	Molpy.Notify('BeachBall version ' + version + ' loaded for SandCastle Builder version ' + SCBversion, 1);
	setInterval(function() {
		Molpy.Notify('1 Refresh', 0);
		Time_to_ONG = (Molpy.NPlength * 1000) - Molpy.ONGelapsed;
		RedundaKitty();
		Ninja();
	}, refreshRate);
}

//Run Main Loop after 1 second startup delay
setTimeout(MainLoop, 1000);

function SpawnRK() {
	Molpy.redactedCountup = Molpy.redactedToggle - 1;
}

<|endoftext|>


<commit_before>////////// API //////////

// To be part of ECMAScript.next
if (!Object.getOwnPropertyDescriptors) {
    Object.getOwnPropertyDescriptors = function (obj) {
        return Object.getOwnPropertyNames(obj).map(function(propName) {
            return Object.getOwnPropertyDescriptor(source, propName);
        });
    };
}

/**
 * The root of all classes that adhere to "the prototypes as classes" protocol.
 * The neat thing is that the class methods "new" and "extend" are automatically
 * inherited by subclasses of this class (because Proto is in their prototype chain).
 */
var Proto = {
    /**
     * Class method: create a new instance and let instance method constructor() initialize it.
     * "this" is the prototype of the new instance.
     */
    new: function () {
        // Alternative: new this.constructor(). But: cannot forward "arguments".
        var instance = Object.create(this);
        if (instance.constructor) {
            instance.constructor.apply(this, arguments);
        }
        return instance;
    },

    /**
     * Class method: subclass "this" (a prototype object used as a class)
     */
    extend: function (subProps) {
        // We cannot set the prototype of "subProps"
        // => copy its contents to a new object that has the right prototype
        var subProto = Object.create(this, Object.getOwnPropertyDescriptors(subProps));

        // Ensure that constructor and prototype point to each other
        if (subProto.constructor) {
            subProto.constructor.prototype = subProto;
        }
        subProto.super = this; // for super-calls
        return subProto;
    },
};

////////// Demo //////////

/***** Code *****
// Superclass
var Person = Proto.extend({
    constructor: function (name) {
        this.name = name;
    },
    describe: function() {
        return "Person called "+this.name;
    },
});

// Subclass
var Worker = Person.extend({
    constructor: function (name, title) {
        Worker.super.constructor.call(this, name);
        this.title = title;
    },
    describe: function () {
        return Worker.super.describe.call(this)+" ("+this.title+")";
    },
});
*/

/***** Interaction *****
var jane = Worker.new("Jane", "CTO"); // normally: new Worker(...)
> Worker.isPrototypeOf(jane) // normally: jane instanceof Worker
true
> jane.describe()
'Person called Jane (CTO)'
*/
<commit_msg>Not setting up constructor.prototype, any more. New: Function.prototype.extend for backward compatibility with constructor functions.<commit_after>////////// API //////////

// To be part of ECMAScript.next
if (!Object.getOwnPropertyDescriptors) {
    Object.getOwnPropertyDescriptors = function (obj) {
        return Object.getOwnPropertyNames(obj).map(function(propName) {
            return Object.getOwnPropertyDescriptor(source, propName);
        });
    };
}

/**
 * The root of all classes that adhere to "the prototypes as classes" protocol.
 * The neat thing is that the class methods "new" and "extend" are automatically
 * inherited by subclasses of this class (because Proto is in their prototype chain).
 */
var Proto = {
    /**
     * Class method: create a new instance and let instance method constructor() initialize it.
     * "this" is the prototype of the new instance.
     */
    new: function () {
        var instance = Object.create(this);
        if (instance.constructor) {
            instance.constructor.apply(this, arguments);
        }
        return instance;
    },

    /**
     * Class method: subclass "this" (a prototype object used as a class)
     */
    extend: function (subProps) {
        // We cannot set the prototype of "subProps"
        // => copy its contents to a new object that has the right prototype
        var subProto = Object.create(this, Object.getOwnPropertyDescriptors(subProps));
        subProto.super = this; // for super-calls
        return subProto;
    },
};

/**
 * Optional: compatibility with constructor functions
 */
Function.prototype.extend = function(subProps) {
    // Let a prototype-as-class extend a constructor function CF.
    // Step 1: append Proto to CF.prototype
    var protoAsClass = Proto.extend.call(this.prototype, Proto);
    // Step 2: the new object is a prototype-as-class => use as such
    return protoAsClass.extend(subProps);
};

////////// Demo //////////

/***** Code *****
// Superclass
var Person = Proto.extend({
    constructor: function (name) {
        this.name = name;
    },
    describe: function() {
        return "Person called "+this.name;
    },
});

// Subclass
var Worker = Person.extend({
    constructor: function (name, title) {
        Worker.super.constructor.call(this, name);
        this.title = title;
    },
    describe: function () {
        return Worker.super.describe.call(this)+" ("+this.title+")";
    },
});
*/

/***** Interaction *****
var jane = Worker.new("Jane", "CTO"); // normally: new Worker(...)
> Worker.isPrototypeOf(jane) // normally: jane instanceof Worker
true
> jane.describe()
'Person called Jane (CTO)'
*/
<|endoftext|>