<commit_before>'use strict';

var processProperties = require('../../../src/template/process_properties');

describe('process_properties.js public API', function() {
  describe('processProperties', function() {
    it('should be a function', function() {
      expect(processProperties).to.be.a('function');
    });
    it('should treat all properties of elements with namespaces (usually SVG) as attributes', function() {
      var result = processProperties({namespace: 'Test', label: 'label', class: 'js-test'});
      expect(result).to.be.a('object');
      expect(result.namespace).to.equal('Test');
      expect(result.attributes).to.deep.equal({namespace: undefined, label: 'label', class: 'js-test'});
    });
    it('should use hooks when enabled', function() {
      var hook = {};
      var value = {};
      var autofocusSpy = jasmine.createSpy('autofocusHook').and.returnValue(hook);
      var result = processProperties({
        Autofocus: value
      }, {
        useHooks: {
          autofocus: autofocusSpy
        }
      });
      jasmineExpect(autofocusSpy).toHaveBeenCalledWith(value);
      expect(result.attributes.Autofocus).to.equal(hook);
    });
    it('should transform attribute names to property names when appropriate', function() {
      var result = processProperties({class: 'js-test'});
      expect(result.className).to.equal('js-test');
      expect(result.class).to.equal(undefined);
    });
    it('should parse style tags into CSS rules', function() {
      var resultFromString = processProperties({style: 'color: orange; text-align: center;'});
      expect(resultFromString.style).to.deep.equal({cssText: 'color: orange; text-align: center;'});
      var resultFromObj = processProperties({style: {color: 'orange', 'text-align': 'center'}});
      expect(resultFromObj.style).to.deep.equal({color: 'orange', 'text-align': 'center'});
    });
  });
});
<commit_msg>Fixing unit test<commit_after>'use strict';

var processProperties = require('../../../src/template/process_properties');

describe('process_properties.js public API', function() {
  describe('processProperties', function() {
    it('should be a function', function() {
      expect(processProperties).to.be.a('function');
    });
    it('should treat all properties of elements with namespaces (usually SVG) as attributes', function() {
      var result = processProperties({namespace: 'Test', label: 'label', class: 'js-test'});
      expect(result).to.be.a('object');
      expect(result.namespace).to.equal('Test');
      expect(result.attributes).to.deep.equal({namespace: undefined, label: 'label', class: 'js-test'});
    });
    it('should use hooks when enabled', function() {
      var hook = {};
      var value = {};
      var autofocusSpy = jasmine.createSpy('autofocusHook').and.returnValue(hook);
      var result = processProperties({
        Autofocus: value
      }, {
        useHooks: {
          autofocus: autofocusSpy
        }
      });
      jasmineExpect(autofocusSpy).toHaveBeenCalledWith(value);
      expect(result.autofocus).to.equal(hook);
    });
    it('should transform attribute names to property names when appropriate', function() {
      var result = processProperties({class: 'js-test'});
      expect(result.className).to.equal('js-test');
      expect(result.class).to.equal(undefined);
    });
    it('should parse style tags into CSS rules', function() {
      var resultFromString = processProperties({style: 'color: orange; text-align: center;'});
      expect(resultFromString.style).to.deep.equal({cssText: 'color: orange; text-align: center;'});
      var resultFromObj = processProperties({style: {color: 'orange', 'text-align': 'center'}});
      expect(resultFromObj.style).to.deep.equal({color: 'orange', 'text-align': 'center'});
    });
  });
});
<|endoftext|>


<commit_before>// Theirs
import React from 'react'
import domtoimage from 'dom-to-image'
import dynamic from 'next/dynamic'
import Dropzone from 'dropperx'

// Ours
import ApiContext from './ApiContext'
import Dropdown from './Dropdown'
import Settings from './Settings'
import Toolbar from './Toolbar'
import Overlay from './Overlay'
import Carbon from './Carbon'
import ExportMenu from './ExportMenu'
import Themes from './Themes'
import TweetButton from './TweetButton'
import {
  LANGUAGES,
  LANGUAGE_MIME_HASH,
  LANGUAGE_MODE_HASH,
  LANGUAGE_NAME_HASH,
  DEFAULT_EXPORT_SIZE,
  COLORS,
  EXPORT_SIZES_HASH,
  DEFAULT_CODE,
  DEFAULT_SETTINGS,
  DEFAULT_LANGUAGE,
  DEFAULT_THEME,
  FONTS
} from '../lib/constants'
import { serializeState, getRouteState } from '../lib/routing'
import { getSettings, unescapeHtml, formatCode, omit } from '../lib/util'
import LanguageIcon from './svg/Language'

const languageIcon = <LanguageIcon />

const BackgroundSelect = dynamic(() => import('./BackgroundSelect'), {
  loading: () => null
})

class Editor extends React.Component {
  static contextType = ApiContext

  constructor(props) {
    super(props)
    this.state = {
      ...DEFAULT_SETTINGS,
      loading: true
    }

    this.export = this.export.bind(this)
    this.upload = this.upload.bind(this)
    this.updateSetting = this.updateSetting.bind(this)
    this.updateLanguage = this.updateLanguage.bind(this)
    this.updateBackground = this.updateBackground.bind(this)
    this.resetDefaultSettings = this.resetDefaultSettings.bind(this)
    this.getCarbonImage = this.getCarbonImage.bind(this)
    this.onDrop = this.onDrop.bind(this)
  }

  async componentDidMount() {
    const { queryState, parameter } = getRouteState(this.props.router)

    // TODO we could create an interface for loading this config, so that it looks identical
    // whether config is loaded from localStorage, gist, or even something like IndexDB
    let gistState
    if (this.context.gist && parameter) {
      const { config, ...gist } = (await this.context.gist.get(parameter)) || {}
      if (typeof config === 'object') {
        this.gist = gist
        gistState = config
      }
    }

    const newState = {
      // Load options from gist or localStorage
      ...(gistState ? gistState : getSettings(localStorage)),
      // and then URL params
      ...queryState,
      loading: false
    }

    // Makes sure the slash in 'application/X' is decoded
    if (newState.language) {
      newState.language = unescapeHtml(newState.language)
    }

    if (newState.fontFamily && !FONTS.find(({ id }) => id === newState.fontFamily)) {
      newState.fontFamily = DEFAULT_SETTINGS.fontFamily
    }

    this.updateState(newState)

    this.isSafari =
      window.navigator &&
      window.navigator.userAgent.indexOf('Safari') !== -1 &&
      window.navigator.userAgent.indexOf('Chrome') === -1
    this.isFirefox =
      window.navigator &&
      window.navigator.userAgent.indexOf('Firefox') !== -1 &&
      window.navigator.userAgent.indexOf('Chrome') === -1
  }

  carbonNode = React.createRef()

  getTheme = () => this.props.themes.find(t => t.id === this.state.theme) || DEFAULT_THEME

  updateState = updates => {
    this.setState(updates, () => {
      if (!this.gist) {
        this.props.onUpdate(this.state)
      }
    })
  }

  updateCode = code => this.updateState({ code })

  async getCarbonImage(
    {
      format,
      type,
      squared = this.state.squaredImage,
      exportSize = (EXPORT_SIZES_HASH[this.state.exportSize] || DEFAULT_EXPORT_SIZE).value,
      includeTransparentRow = false
    } = { format: 'png' }
  ) {
    // if safari, get image from api
    const isPNG = format !== 'svg'
    if (this.context.image && this.isSafari && isPNG) {
      const themeConfig = this.getTheme()
      // pull from custom theme highlights, or state highlights
      const encodedState = serializeState({
        ...this.state,
        highlights: { ...themeConfig.highlights, ...this.state.highlights }
      })
      return this.context.image(encodedState)
    }

    const node = this.carbonNode.current

    const map = new Map()
    const undoMap = value => {
      map.forEach((value, node) => (node.innerHTML = value))
      return value
    }

    if (isPNG) {
      node.querySelectorAll('span[role="presentation"]').forEach(node => {
        if (node.innerText && node.innerText.match(/%[A-Fa-f0-9]{2}/)) {
          map.set(node, node.innerHTML)
          node.innerText.match(/%[A-Fa-f0-9]{2}/g).forEach(t => {
            node.innerText = node.innerText.replace(t, encodeURIComponent(t))
          })
        }
      })
    }

    const width = node.offsetWidth * exportSize
    const height = squared ? node.offsetWidth * exportSize : node.offsetHeight * exportSize

    const config = {
      style: {
        transform: `scale(${exportSize})`,
        'transform-origin': 'center',
        background: squared ? this.state.backgroundColor : 'none'
      },
      filter: n => {
        if (n.className) {
          if (String(n.className).indexOf('eliminateOnRender') > -1) {
            return false
          }
          if (String(n.className).indexOf('twitter-png-fix') > -1) {
            return includeTransparentRow
          }
        }
        return true
      },
      width,
      height
    }

    // current font-family used
    const fontFamily = this.state.fontFamily
    try {
      if (type === 'blob') {
        if (format === 'svg') {
          return (
            domtoimage
              .toSvg(node, config)
              .then(dataUrl =>
                dataUrl
                  .replace(/ /g, ' ')
                  // https://github.com/tsayen/dom-to-image/blob/fae625bce0970b3a039671ea7f338d05ecb3d0e8/src/dom-to-image.js#L551
                  .replace(/%23/g, '#')
                  .replace(/%0A/g, '\n')
                  // remove other fonts which are not used
                  .replace(
                    new RegExp('@font-face\\s+{\\s+font-family: (?!"*' + fontFamily + ').*?}', 'g'),
                    ''
                  )
              )
              // https://stackoverflow.com/questions/7604436/xmlparseentityref-no-name-warnings-while-loading-xml-into-a-php-file
              .then(dataUrl => dataUrl.replace(/&(?!#?[a-z0-9]+;)/g, '&'))
              .then(uri => uri.slice(uri.indexOf(',') + 1))
              .then(data => new Blob([data], { type: 'image/svg+xml' }))
              .then(data => window.URL.createObjectURL(data))
          )
        }

        return await domtoimage.toBlob(node, config).then(blob => window.URL.createObjectURL(blob))
      }

      // Twitter needs regular dataurls
      return await domtoimage.toPng(node, config)
    } finally {
      undoMap()
    }
  }

  updateSetting(key, value) {
    this.updateState({ [key]: value })
    if (Object.prototype.hasOwnProperty.call(DEFAULT_SETTINGS, key) && key !== 'preset') {
      this.updateState({ preset: null })
    }
  }

  export(format = 'png', options = {}) {
    const link = document.createElement('a')

    const prefix = options.filename || 'carbon'

    return this.getCarbonImage({ format, type: 'blob' }).then(url => {
      if (format !== 'open') {
        link.download = `${prefix}.${format}`
      }
      if (this.isFirefox) {
        link.target = '_blank'
      }
      link.href = url
      document.body.appendChild(link)
      link.click()
      link.remove()
    })
  }

  resetDefaultSettings() {
    this.updateState(DEFAULT_SETTINGS)
    this.props.onReset()
  }

  upload() {
    this.getCarbonImage({ format: 'png', includeTransparentRow: true }).then(
      this.context.tweet.bind(null, this.state.code || DEFAULT_CODE)
    )
  }

  onDrop([file]) {
    if (isImage(file)) {
      this.updateState({
        backgroundImage: file.content,
        backgroundImageSelection: null,
        backgroundMode: 'image',
        preset: null
      })
    } else {
      this.updateState({ code: file.content, language: 'auto' })
    }
  }

  updateLanguage(language) {
    if (language) {
      this.updateSetting('language', language.mime || language.mode)
    }
  }

  updateBackground({ photographer, ...changes } = {}) {
    if (photographer) {
      this.updateState(({ code = DEFAULT_CODE }) => ({
        ...changes,
        code: code + `\n\n// Photo by ${photographer.name} on Unsplash`,
        preset: null
      }))
    } else {
      this.updateState({ ...changes, preset: null })
    }
  }

  updateTheme = theme => this.updateState({ theme })
  updateHighlights = updates =>
    this.setState(({ highlights = {} }) => ({
      highlights: {
        ...highlights,
        ...updates
      }
    }))

  createTheme = theme => {
    this.props.updateThemes(themes => [theme, ...themes])
    this.updateTheme(theme.id)
  }

  removeTheme = id => {
    this.props.updateThemes(themes => themes.filter(t => t.id !== id))
    if (this.state.theme.id === id) {
      this.updateTheme(DEFAULT_THEME.id)
    }
  }

  applyPreset = ({ id: preset, ...settings }) => this.updateState({ preset, ...settings })

  format = () =>
    formatCode(this.state.code)
      .then(this.updateCode)
      .catch(() => {
        // create toast here in the future
      })

  render() {
    const {
      highlights,
      language,
      backgroundColor,
      backgroundImage,
      backgroundMode,
      code,
      exportSize
    } = this.state

    const config = omit(this.state, ['code'])

    const theme = this.getTheme()

    return (

        <Toolbar>
          <Themes
            theme={theme}
            highlights={highlights}
            update={this.updateTheme}
            updateHighlights={this.updateHighlights}
            remove={this.removeTheme}
            create={this.createTheme}
            themes={this.props.themes}
          />
          <Dropdown
            title="Language"
            icon={languageIcon}
            selected={
              LANGUAGE_NAME_HASH[language] ||
              LANGUAGE_MIME_HASH[language] ||
              LANGUAGE_MODE_HASH[language] ||
              LANGUAGE_MODE_HASH[DEFAULT_LANGUAGE]
            }
            list={LANGUAGES}
            onChange={this.updateLanguage}
          />
          <BackgroundSelect
            onChange={this.updateBackground}
            mode={backgroundMode}
            color={backgroundColor}
            image={backgroundImage}
            carbonRef={this.carbonNode.current}
          />
          <Settings
            {...config}
            onChange={this.updateSetting}
            resetDefaultSettings={this.resetDefaultSettings}
            format={this.format}
            applyPreset={this.applyPreset}
            getCarbonImage={this.getCarbonImage}
          />

            <TweetButton onClick={this.upload} />
            <ExportMenu
              onChange={this.updateSetting}
              export={this.export}
              exportSize={exportSize}
              backgroundImage={backgroundImage}
            />

        </Toolbar>

        <Dropzone accept="image/*, text/*, application/*" onDrop={this.onDrop}>
          {({ canDrop }) => (
            <Overlay
              isOver={canDrop}
              title={`Drop your file here to import ${canDrop ? '✋' : '✊'}`}
            >
              {/*key ensures Carbon's internal language state is updated when it's changed by Dropdown*/}
              <Carbon
                key={language}
                ref={this.carbonNode}
                config={this.state}
                onChange={this.updateCode}
                loading={this.state.loading}
                theme={theme}
              >
                {code != null ? code : DEFAULT_CODE}
              </Carbon>
            </Overlay>
          )}
        </Dropzone>

    )
  }
}

function isImage(file) {
  return file.type.split('/')[0] === 'image'
}

Editor.defaultProps = {
  onUpdate: () => {},
  onReset: () => {}
}

export default Editor
<commit_msg>move @font-face into function component<commit_after>// Theirs
import React from 'react'
import domtoimage from 'dom-to-image'
import dynamic from 'next/dynamic'
import Dropzone from 'dropperx'

// Ours
import ApiContext from './ApiContext'
import Dropdown from './Dropdown'
import Settings from './Settings'
import Toolbar from './Toolbar'
import Overlay from './Overlay'
import Carbon from './Carbon'
import ExportMenu from './ExportMenu'
import Themes from './Themes'
import TweetButton from './TweetButton'
import {
  LANGUAGES,
  LANGUAGE_MIME_HASH,
  LANGUAGE_MODE_HASH,
  LANGUAGE_NAME_HASH,
  DEFAULT_EXPORT_SIZE,
  COLORS,
  EXPORT_SIZES_HASH,
  DEFAULT_CODE,
  DEFAULT_SETTINGS,
  DEFAULT_LANGUAGE,
  DEFAULT_THEME,
  FONTS
} from '../lib/constants'
import { serializeState, getRouteState } from '../lib/routing'
import { getSettings, unescapeHtml, formatCode, omit } from '../lib/util'
import LanguageIcon from './svg/Language'

const languageIcon = <LanguageIcon />

const BackgroundSelect = dynamic(() => import('./BackgroundSelect'), {
  loading: () => null
})

class Editor extends React.Component {
  static contextType = ApiContext

  constructor(props) {
    super(props)
    this.state = {
      ...DEFAULT_SETTINGS,
      loading: true
    }

    this.export = this.export.bind(this)
    this.upload = this.upload.bind(this)
    this.updateSetting = this.updateSetting.bind(this)
    this.updateLanguage = this.updateLanguage.bind(this)
    this.updateBackground = this.updateBackground.bind(this)
    this.resetDefaultSettings = this.resetDefaultSettings.bind(this)
    this.getCarbonImage = this.getCarbonImage.bind(this)
    this.onDrop = this.onDrop.bind(this)
  }

  async componentDidMount() {
    const { queryState, parameter } = getRouteState(this.props.router)

    // TODO we could create an interface for loading this config, so that it looks identical
    // whether config is loaded from localStorage, gist, or even something like IndexDB
    let gistState
    if (this.context.gist && parameter) {
      const { config, ...gist } = (await this.context.gist.get(parameter)) || {}
      if (typeof config === 'object') {
        this.gist = gist
        gistState = config
      }
    }

    const newState = {
      // Load options from gist or localStorage
      ...(gistState ? gistState : getSettings(localStorage)),
      // and then URL params
      ...queryState,
      loading: false
    }

    // Makes sure the slash in 'application/X' is decoded
    if (newState.language) {
      newState.language = unescapeHtml(newState.language)
    }

    if (newState.fontFamily && !FONTS.find(({ id }) => id === newState.fontFamily)) {
      newState.fontFamily = DEFAULT_SETTINGS.fontFamily
    }

    this.updateState(newState)

    this.isSafari =
      window.navigator &&
      window.navigator.userAgent.indexOf('Safari') !== -1 &&
      window.navigator.userAgent.indexOf('Chrome') === -1
    this.isFirefox =
      window.navigator &&
      window.navigator.userAgent.indexOf('Firefox') !== -1 &&
      window.navigator.userAgent.indexOf('Chrome') === -1
  }

  carbonNode = React.createRef()

  getTheme = () => this.props.themes.find(t => t.id === this.state.theme) || DEFAULT_THEME

  updateState = updates => {
    this.setState(updates, () => {
      if (!this.gist) {
        this.props.onUpdate(this.state)
      }
    })
  }

  updateCode = code => this.updateState({ code })

  async getCarbonImage(
    {
      format,
      type,
      squared = this.state.squaredImage,
      exportSize = (EXPORT_SIZES_HASH[this.state.exportSize] || DEFAULT_EXPORT_SIZE).value,
      includeTransparentRow = false
    } = { format: 'png' }
  ) {
    // if safari, get image from api
    const isPNG = format !== 'svg'
    if (this.context.image && this.isSafari && isPNG) {
      const themeConfig = this.getTheme()
      // pull from custom theme highlights, or state highlights
      const encodedState = serializeState({
        ...this.state,
        highlights: { ...themeConfig.highlights, ...this.state.highlights }
      })
      return this.context.image(encodedState)
    }

    const node = this.carbonNode.current

    const map = new Map()
    const undoMap = value => {
      map.forEach((value, node) => (node.innerHTML = value))
      return value
    }

    if (isPNG) {
      node.querySelectorAll('span[role="presentation"]').forEach(node => {
        if (node.innerText && node.innerText.match(/%[A-Fa-f0-9]{2}/)) {
          map.set(node, node.innerHTML)
          node.innerText.match(/%[A-Fa-f0-9]{2}/g).forEach(t => {
            node.innerText = node.innerText.replace(t, encodeURIComponent(t))
          })
        }
      })
    }

    const width = node.offsetWidth * exportSize
    const height = squared ? node.offsetWidth * exportSize : node.offsetHeight * exportSize

    const config = {
      style: {
        transform: `scale(${exportSize})`,
        'transform-origin': 'center',
        background: squared ? this.state.backgroundColor : 'none'
      },
      filter: n => {
        if (n.className) {
          if (String(n.className).indexOf('eliminateOnRender') > -1) {
            return false
          }
          if (String(n.className).indexOf('twitter-png-fix') > -1) {
            return includeTransparentRow
          }
        }
        return true
      },
      width,
      height
    }

    // current font-family used
    const fontFamily = this.state.fontFamily
    try {
      if (type === 'blob') {
        if (format === 'svg') {
          return (
            domtoimage
              .toSvg(node, config)
              .then(dataUrl =>
                dataUrl
                  .replace(/ /g, ' ')
                  // https://github.com/tsayen/dom-to-image/blob/fae625bce0970b3a039671ea7f338d05ecb3d0e8/src/dom-to-image.js#L551
                  .replace(/%23/g, '#')
                  .replace(/%0A/g, '\n')
                  // remove other fonts which are not used
                  .replace(
                    new RegExp('@font-face\\s+{\\s+font-family: (?!"*' + fontFamily + ').*?}', 'g'),
                    ''
                  )
              )
              // https://stackoverflow.com/questions/7604436/xmlparseentityref-no-name-warnings-while-loading-xml-into-a-php-file
              .then(dataUrl => dataUrl.replace(/&(?!#?[a-z0-9]+;)/g, '&'))
              .then(uri => uri.slice(uri.indexOf(',') + 1))
              .then(data => new Blob([data], { type: 'image/svg+xml' }))
              .then(data => window.URL.createObjectURL(data))
          )
        }

        return await domtoimage.toBlob(node, config).then(blob => window.URL.createObjectURL(blob))
      }

      // Twitter needs regular dataurls
      return await domtoimage.toPng(node, config)
    } finally {
      undoMap()
    }
  }

  updateSetting(key, value) {
    this.updateState({ [key]: value })
    if (Object.prototype.hasOwnProperty.call(DEFAULT_SETTINGS, key) && key !== 'preset') {
      this.updateState({ preset: null })
    }
  }

  export(format = 'png', options = {}) {
    const link = document.createElement('a')

    const prefix = options.filename || 'carbon'

    return this.getCarbonImage({ format, type: 'blob' }).then(url => {
      if (format !== 'open') {
        link.download = `${prefix}.${format}`
      }
      if (this.isFirefox) {
        link.target = '_blank'
      }
      link.href = url
      document.body.appendChild(link)
      link.click()
      link.remove()
    })
  }

  resetDefaultSettings() {
    this.updateState(DEFAULT_SETTINGS)
    this.props.onReset()
  }

  upload() {
    this.getCarbonImage({ format: 'png', includeTransparentRow: true }).then(
      this.context.tweet.bind(null, this.state.code || DEFAULT_CODE)
    )
  }

  onDrop([file]) {
    if (isImage(file)) {
      this.updateState({
        backgroundImage: file.content,
        backgroundImageSelection: null,
        backgroundMode: 'image',
        preset: null
      })
    } else {
      this.updateState({ code: file.content, language: 'auto' })
    }
  }

  updateLanguage(language) {
    if (language) {
      this.updateSetting('language', language.mime || language.mode)
    }
  }

  updateBackground({ photographer, ...changes } = {}) {
    if (photographer) {
      this.updateState(({ code = DEFAULT_CODE }) => ({
        ...changes,
        code: code + `\n\n// Photo by ${photographer.name} on Unsplash`,
        preset: null
      }))
    } else {
      this.updateState({ ...changes, preset: null })
    }
  }

  updateTheme = theme => this.updateState({ theme })
  updateHighlights = updates =>
    this.setState(({ highlights = {} }) => ({
      highlights: {
        ...highlights,
        ...updates
      }
    }))

  createTheme = theme => {
    this.props.updateThemes(themes => [theme, ...themes])
    this.updateTheme(theme.id)
  }

  removeTheme = id => {
    this.props.updateThemes(themes => themes.filter(t => t.id !== id))
    if (this.state.theme.id === id) {
      this.updateTheme(DEFAULT_THEME.id)
    }
  }

  applyPreset = ({ id: preset, ...settings }) => this.updateState({ preset, ...settings })

  format = () =>
    formatCode(this.state.code)
      .then(this.updateCode)
      .catch(() => {
        // create toast here in the future
      })

  render() {
    const {
      highlights,
      language,
      backgroundColor,
      backgroundImage,
      backgroundMode,
      code,
      exportSize
    } = this.state

    const config = omit(this.state, ['code'])

    const theme = this.getTheme()

    return (

        <Toolbar>
          <Themes
            theme={theme}
            highlights={highlights}
            update={this.updateTheme}
            updateHighlights={this.updateHighlights}
            remove={this.removeTheme}
            create={this.createTheme}
            themes={this.props.themes}
          />
          <Dropdown
            title="Language"
            icon={languageIcon}
            selected={
              LANGUAGE_NAME_HASH[language] ||
              LANGUAGE_MIME_HASH[language] ||
              LANGUAGE_MODE_HASH[language] ||
              LANGUAGE_MODE_HASH[DEFAULT_LANGUAGE]
            }
            list={LANGUAGES}
            onChange={this.updateLanguage}
          />
          <BackgroundSelect
            onChange={this.updateBackground}
            mode={backgroundMode}
            color={backgroundColor}
            image={backgroundImage}
            carbonRef={this.carbonNode.current}
          />
          <Settings
            {...config}
            onChange={this.updateSetting}
            resetDefaultSettings={this.resetDefaultSettings}
            format={this.format}
            applyPreset={this.applyPreset}
            getCarbonImage={this.getCarbonImage}
          />

            <TweetButton onClick={this.upload} />
            <ExportMenu
              onChange={this.updateSetting}
              export={this.export}
              exportSize={exportSize}
              backgroundImage={backgroundImage}
            />

        </Toolbar>

        <Dropzone accept="image/*, text/*, application/*" onDrop={this.onDrop}>
          {({ canDrop }) => (
            <Overlay
              isOver={canDrop}
              title={`Drop your file here to import ${canDrop ? '✋' : '✊'}`}
            >
              {/*key ensures Carbon's internal language state is updated when it's changed by Dropdown*/}
              <Carbon
                key={language}
                ref={this.carbonNode}
                config={this.state}
                onChange={this.updateCode}
                loading={this.state.loading}
                theme={theme}
              >
                {code != null ? code : DEFAULT_CODE}
              </Carbon>
            </Overlay>
          )}
        </Dropzone>
        <FontFace {...config} />

    )
  }
}

function FontFace(config) {
  return (

  )
}

function isImage(file) {
  return file.type.split('/')[0] === 'image'
}

Editor.defaultProps = {
  onUpdate: () => {},
  onReset: () => {}
}

export default Editor
<|endoftext|>


<commit_before>(function(global) {
  'use strict';

  // Dog constructor
  //-----------------
  function Dog(params) {

    // If initialized without the `new` keyword
    // detect and re-initialize properly to prevent
    // pollution of the global namespace.
    if (!(this instanceof Dog)) {
      return new Dog(params);
    }

    // Cache reference to `this`.
    var _this = this;

    // Set params to object literal if left `undefined`.
    params = params || {};

    // Set public static properties on `Dog`.
    this.owner = params.owner || "Jessica";
    this.name = params.name || "Crap Dog";
    this.age = params.age || 13;
    this.color = params.color || "doo doo brown";
    this.breed = params.breed || "Turd Terrier";
    this.hobbies = params.hobbies || ["destroying furniture", "knocking the kids over", "dragging my butt on the white carpet"];

    // Add sounds with an [IIFE](http://en.wikipedia.org/wiki/Immediately-invoked_function_expression).
    this.sounds = (function(sounds) {
      if (sounds instanceof Array) {
        return _this.defaultSounds.concat(sounds);
      }

      if (typeof sounds === "string") {
        return _this.defaultSounds.concat(sounds.split(","));
      }

      return _this.defaultSounds;
    })(params.sounds);

  }

  // Prototype properties
  //------------------------
  // These properties and methods are shared amongst all instances of `Dog`.
  // They change accross the board when the prototype changes.

  // Array: Typical dog sounds.
  Dog.prototype.defaultSounds = ["woof", "bow wow", "growl"];

  // Method for generating dog bio. Returns a string.
  Dog.prototype.bio = function() {
    var paragraph = [];

    paragraph.push(sentences.intro(this));
    paragraph.push(sentences.description(this));
    paragraph.push(sentences.activities(this));

    return paragraph.join(" ");
  };

  // Private methods
  //--------------------

  // Object used for generating sentences.
  var sentences = {
    intro: function(dog) {
      return "Hey guys I'm " + dog.owner + "'s canine companion, " + dog.name + ".";
    },
    description: function(dog) {
      return "I am a " + dog.age + " year old " + dog.color + " '" + dog.breed + "'.";
    },
    activities: function(dog) {
      var hobbies = (typeof dog.hobbies === "string" ? dog.hobbies : dog.hobbies.join(" and "));
      var sounds = (function(sounds) {
        var ss = [randomValue(sounds) + "!", randomValue(sounds) + "!"];
        return ss.join(" ");
      })(dog.sounds);

      return "My favorite activities include " + hobbies + ". " +
        "Plus I stay up all night going \"" + sounds + "\", " +
        "destroying any chance of " + dog.owner.split(' ')[0] + " getting 8hrs of sleep. >;]";
    }
  };

  // Utility functions
  function randomValue(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
  }

  // Global Binding/Exports
  //-------------------------

  // AMD
  if (typeof define === 'function' && define.amd) {
    define(function() {
      return Dog;
    });

    // Node and other CommonJS-like environments that support module.exports.
  } else if (typeof module !== 'undefined' && module.exports) {
    module.exports = Dog;

    // Browser
  } else {
    global.Dog = Dog;
  }

})(this);
<commit_msg>add bark method<commit_after>(function(global) {
  'use strict';

  // Dog constructor
  //-----------------
  function Dog(params) {

    // If initialized without the `new` keyword
    // detect and re-initialize properly to prevent
    // pollution of the global namespace.
    if (!(this instanceof Dog)) {
      return new Dog(params);
    }

    // Cache reference to `this`.
    var _this = this;

    // Set params to object literal if left `undefined`.
    params = params || {};

    // Set public static properties on `Dog`.
    this.owner = params.owner || "Jessica";
    this.name = params.name || "Crap Dog";
    this.age = params.age || 13;
    this.color = params.color || "doo doo brown";
    this.breed = params.breed || "Turd Terrier";
    this.hobbies = params.hobbies || ["destroying furniture", "knocking the kids over", "dragging my butt on the white carpet"];

    // Add sounds with an [IIFE](http://en.wikipedia.org/wiki/Immediately-invoked_function_expression).
    this.sounds = (function(sounds) {
      if (sounds instanceof Array) {
        return _this.defaultSounds.concat(sounds);
      }

      if (typeof sounds === "string") {
        return _this.defaultSounds.concat(sounds.split(","));
      }

      return _this.defaultSounds;
    })(params.sounds);

  }

  // Prototype properties
  //------------------------
  // These properties and methods are shared amongst all instances of `Dog`.
  // They change accross the board when the prototype changes.

  // Array: Typical dog sounds.
  Dog.prototype.defaultSounds = ["woof", "bow wow", "growl"];

  // Method for generating dog bio. Returns a string.
  Dog.prototype.bio = function() {
    var paragraph = [];

    paragraph.push(sentences.intro(this));
    paragraph.push(sentences.description(this));
    paragraph.push(sentences.activities(this));

    return paragraph.join(" ");
  };

  // Method for barking it up. Returns a string.
  Dog.prototype.bark = function(str) {
    var prefix = this.name + ' says: ',
      ret = prefix + ((typeof str === 'string') ? str : randomValue(this.sounds));
    console.log(ret);
    return ret;
  };

  // Private methods
  //--------------------

  // Object used for generating sentences.
  var sentences = {
    intro: function(dog) {
      return "Hey guys I'm " + dog.owner + "'s canine companion, " + dog.name + ".";
    },
    description: function(dog) {
      return "I am a " + dog.age + " year old " + dog.color + " '" + dog.breed + "'.";
    },
    activities: function(dog) {
      var hobbies = (typeof dog.hobbies === "string" ? dog.hobbies : dog.hobbies.join(" and "));
      var sounds = (function(sounds) {
        var ss = [randomValue(sounds) + "!", randomValue(sounds) + "!"];
        return ss.join(" ");
      })(dog.sounds);

      return "My favorite activities include " + hobbies + ". " +
        "Plus I stay up all night going \"" + sounds + "\", " +
        "destroying any chance of " + dog.owner.split(' ')[0] + " getting 8hrs of sleep. >;]";
    }
  };

  // Utility functions
  function randomValue(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
  }

  // Global Binding/Exports
  //-------------------------

  // AMD
  if (typeof define === 'function' && define.amd) {
    define(function() {
      return Dog;
    });

    // Node and other CommonJS-like environments that support module.exports.
  } else if (typeof module !== 'undefined' && module.exports) {
    module.exports = Dog;

    // Browser
  } else {
    global.Dog = Dog;
  }

})(this);
<|endoftext|>


<commit_before>
'use strict';

const assert = require ('assert');
const Duplex = require('stream').Duplex;

/**
 * Creates in memory writable and readable stream
 * @return {MemDuplex} a MemDuplex instance
 */
class MemDuplex extends Duplex {
    constructor() {
        super({ highWaterMark: 8 * 1024 * 1024 });   // 8MB
        this.buffers = [];
        this.cur = 0;
        // Once writable stream is finished it will emit a finish
        // event
        this.once('finish', () => {
            this._read();
        });
    }
    _write(chunk, enc, cb) {
        assert(Buffer.isBuffer(chunk));
        this.buffers.push(chunk);
        this._read();
        cb();
    }
    _read() {
        while (this.cur < this.buffers.length) {
            this.push(this.buffers[this.cur], 'binary');
            this.cur++;
        }
        // finished is property of writable stream
        // indicating writing is done.
        // Once the writing is done and we have pushed
        // out everything buffered, we're done
        if (this.cur >= this.buffers.length && this._writableState.finished) {
            this.push(null); // End of buffer
        }
    }
}

module.exports = MemDuplex;
<commit_msg>Check for when push to buffer is false and break if so<commit_after>
'use strict';

const assert = require ('assert');
const Duplex = require('stream').Duplex;

/**
 * Creates in memory writable and readable stream
 * @return {MemDuplex} a MemDuplex instance
 */
class MemDuplex extends Duplex {
    constructor() {
        super({ highWaterMark: 8 * 1024 * 1024 });   // 8MB
        this.buffers = [];
        this.cur = 0;
        // Once writable stream is finished it will emit a finish
        // event
        this.once('finish', () => {
            this._read();
        });
    }
    _write(chunk, enc, cb) {
        assert(Buffer.isBuffer(chunk));
        this.buffers.push(chunk);
        this._read();
        cb();
    }
    _read() {
        while (this.cur < this.buffers.length) {
            const pushed = this.push(this.buffers[this.cur], 'binary');
            this.cur++;
            if (!pushed) {
                break;
            }
        }
        // finished is property of writable stream
        // indicating writing is done.
        // Once the writing is done and we have pushed
        // out everything buffered, we're done
        if (this.cur >= this.buffers.length && this._writableState.finished) {
            this.push(null); // End of buffer
        }
    }
}

module.exports = MemDuplex;
<|endoftext|>


<commit_before>/* UMD.define */ (function (root, factory) {
    if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } else { root.returnExports = factory(); window.dom = factory(); }
}(this, function () {
    //  convenience library for common DOM methods
    //      dom()
    //          create dom nodes
    //      dom.style()
    //          set/get node style
    //      dom.attr()
    //          set/get attributes
    //      dom.destroy()
    //          obliterates a node
    //      dom.box()
    //          get node dimensions
    //      dom.uid()
    //          get a unique ID (not dom specific)
    //
    var
        isDimension = {
            width:1,
            height:1,
            top:1,
            left:1,
            right:1,
            bottom:1,
            maxWidth:1,
            'max-width':1,
            minWidth:1,
            'min-width':1,
            maxHeight:1,
            'max-height':1
        },
        uids = {},
        destroyer = document.createElement('div');

    function uid(type){
        if(!uids[type]){
            uids[type] = [];
        }
        var id = type + '-' + (uids[type].length + 1);
        uids[type].push(id);
        return id;
    }

    function isNode(item){
        // safer test for custom elements in FF (with wc shim)
        return typeof item === 'object' && typeof item.innerHTML === 'string';
    }

    function getNode(item){

        if(!item){ return item; }
        if(typeof item === 'string'){
            return document.getElementById(item);
        }
        // de-jqueryify
        return item.get ? item.get(0) :
            // item is a dom node
            item;
    }

    function byId(id){
        return getNode(id);
    }

    function style(node, prop, value){
        // get/set node style(s)
        //      prop: string or object
        //
        var key, computed;
        if(typeof prop === 'object'){
            // object setter
            for(key in prop){
                if(prop.hasOwnProperty(key)){
                    style(node, key, prop[key]);
                }
            }
            return null;
        }else if(value !== undefined){
            // property setter
            if(typeof value === 'number' && isDimension[prop]){
                value += 'px';
            }
            node.style[prop] = value;

            if(prop === 'userSelect'){
                value = !!value ? 'text' : 'none';
                style(node, {
                    webkitTouchCallout: value,
                    webkitUserSelect: value,
                    khtmlUserSelect: value,
                    mozUserSelect: value,
                    msUserSelect: value
                });
            }
        }

        // getter, if a simple style
        if(node.style[prop]){
            if(isDimension[prop]){
                return parseInt(node.style[prop], 10);
            }
            return node.style[prop];
        }

        // getter, computed
        computed = getComputedStyle(node, prop);
        if(computed[prop]){
            if(/\d/.test(computed[prop])){
                return parseInt(computed[prop], 10);
            }
            return computed[prop];
        }
        return '';
    }

    function attr(node, prop, value){
        // get/set node attribute(s)
        //      prop: string or object
        //
        var key;
        if(typeof prop === 'object'){
            for(key in prop){
                if(prop.hasOwnProperty(key)){
                    attr(node, key, prop[key]);
                }
            }
            return null;
        }
        else if(value !== undefined){
            if(prop === 'text' || prop === 'html' || prop === 'innerHTML'){
                node.innerHTML = value;
            }else{
                node.setAttribute(prop, value);
            }
        }

        return node.getAttribute(prop);
    }

    function box(node){
        if(node === window){
            return {
                width: node.innerWidth,
                height: node.innerHeight
            };
        }
        // node dimensions
        // returned object is immutable
        // add scroll positioning and convenience abbreviations
        var
            dimensions = getNode(node).getBoundingClientRect(),
            box = {
                top: dimensions.top,
                right: dimensions.right,
                bottom: dimensions.bottom,
                left: dimensions.left,
                height: dimensions.height,
                h: dimensions.height,
                width: dimensions.width,
                w: dimensions.width,
                scrollY: window.scrollY,
                scrollX: window.scrollX,
                x: dimensions.left + window.pageXOffset,
                y: dimensions.top + window.pageYOffset
            };

        return box;
    }

    function query(node, selector){
        if(!selector){
            selector = node;
            node = document;
        }
        var nodes = node.querySelectorAll(selector);

        // none found; return [] or null?
        if(!nodes.length){ return []; }

        // only one found, return single node
        if(nodes.length === 1){ return nodes[0];}

        // multiple found; convert to Array and return it
        return Array.prototype.slice.call(nodes);

    }

    function toDom(html, options, parent){
        // create a node from an HTML string
        var node = dom('div', {html: html});
        parent = byId(parent || options);
        if(parent){
            while(node.firstChild){
                parent.appendChild(node.firstChild);
            }
            return node.firstChild;
        }
        if(html.indexOf('<') !== 0){
            return node;
        }
        return node.firstChild;
    }

    function toFrag(html){
        var frag = document.createDocumentFragment();
        frag.innerHTML = html;
        return frag;
    }

    function dom(nodeType, options, parent, prepend){
        // create a node
        // if first argument is a string and starts with <, it is assumed
        // to use toDom, and creates a node from HTML. Optional second arg is
        // parent to append to
        // else:
        //      nodeType: string, type of node to create
        //      options: object with style, className, or attr properties
        //          (can also be objects)
        //      parent: Node, optional node to append to
        //      prepend: truthy, to append node as the first child
        //
        if(nodeType.indexOf('<') === 0){
            return toDom(nodeType, options, parent);
        }

        options = options || {};
        var
            className = options.css || options.className,
            node = document.createElement(nodeType);

        parent = getNode(parent);

        if(className){
            node.className = className;
        }

        if(options.html || options.innerHTML){
            node.innerHTML = options.html || options.innerHTML;
        }

        if(options.cssText){
            node.style.cssText = options.cssText;
        }

        if(options.id){
            node.id = options.id;
        }

        if(options.style){
            style(node, options.style);
        }

        if(options.attr){
            attr(node, options.attr);
        }

        if(parent && isNode(parent)){
            if(prepend && parent.hasChildNodes()){
                parent.insertBefore(node, parent.children[0]);
            }else{
                parent.appendChild(node);
            }
        }

        return node;
    }

    function destroy(node){
        // destroys a node completely
        //
        if(node) {
            destroyer.appendChild(node);
            destroyer.innerHTML = '';
        }
    }

    function clean(node, dispose){
        //	Removes all child nodes
        //		dispose: destroy child nodes
        if(dispose){
            while(node.children.length){
                destroy(node.children[0]);
            }
            return;
        }
        while(node.children.length){
            node.removeChild(node.children[0]);
        }
    }

    function ancestor (node, selector){
        // gets the ancestor of node based on selector criteria
        // useful for getting the target node when a child node is clicked upon
        //
        // USAGE
        //      on.selector(childNode, '.app.active');
        //      on.selector(childNode, '#thinger');
        //      on.selector(childNode, 'div');
        //	DOES NOT SUPPORT:
        //		combinations of above
        var
            test,
            parent = node;

        if(selector.indexOf('.') === 0){
            // className
            selector = selector.replace('.', ' ').trim();
            test = function(n){
                return n.classList.contains(selector);
            };
        }
        else if(selector.indexOf('#') === 0){
            // node id
            selector = selector.replace('#', '').trim();
            test = function(n){
                return n.id === selector;
            };
        }
        else if(selector.indexOf('[') > -1){
            // attribute
            console.error('attribute selectors are not yet supported');
        }
        else{
            // assuming node name
            selector = selector.toUpperCase();
            test = function(n){
                return n.nodeName === selector;
            };
        }

        while(parent){
            if(parent === document.body || parent === document){ return false; }
            if(test(parent)){ break; }
            parent = parent.parentNode;
        }

        return parent;
    }

    dom.classList = {
        remove: function(node, names){
            if(!node || !names){
                console.error('dom.classList.remove should include a node and a className');
                return;
            }
            names = Array.isArray(names) ? names : names.indexOf(' ') > -1 ? names.trim().split(' ') : [names];
            names.forEach(function(name){
                if(name){
                    node.classList.remove(name.trim());
                }
            });
        },
        add: function(node, names){
            if(!node || !names){
                return;
            }
            names = Array.isArray(names) ? names : names.indexOf(' ') > -1 ? names.trim().split(' ') : [names];
            names.forEach(function(name){
                if(name){
                    node.classList.add(name.trim());
                }
            });
        },
        contains: function(node, name){
            if(!node || !name){
                return false;
            }
            return node.classList.contains(name);
        },
        toggle: function(node, name){
            if(!node || !name){
                return null;
            }
            return node.classList.toggle(name);
        }
    };

    if (!window.requestAnimationFrame) {
        dom.requestAnimationFrame = function(callback){
            setTimeout(callback, 0);
        };
    }else{
        dom.requestAnimationFrame = function(cb){
            window.requestAnimationFrame(cb);
        };
    }

    dom.clean = clean;
    dom.query = query;
    dom.byId = byId;
    dom.attr = attr;
    dom.box = box;
    dom.style = style;
    dom.destroy = destroy;
    dom.uid = uid;
    dom.isNode = isNode;
    dom.ancestor = ancestor;
    dom.toDom = toDom;
    dom.toFrag = toFrag;

    return dom;
}));
<commit_msg>Add custom loader to UMD<commit_after>/* UMD.define */ (function (root, factory) {
    if (typeof customLoader === 'function'){ customLoader(factory, 'dom'); }else if (typeof define === 'function' && define.amd) { define([], factory); } else if (typeof exports === 'object') { module.exports = factory(); } else { root.returnExports = factory(); window.dom = factory(); }
}(this, function () {
    //  convenience library for common DOM methods
    //      dom()
    //          create dom nodes
    //      dom.style()
    //          set/get node style
    //      dom.attr()
    //          set/get attributes
    //      dom.destroy()
    //          obliterates a node
    //      dom.box()
    //          get node dimensions
    //      dom.uid()
    //          get a unique ID (not dom specific)
    //
    var
        isDimension = {
            width:1,
            height:1,
            top:1,
            left:1,
            right:1,
            bottom:1,
            maxWidth:1,
            'max-width':1,
            minWidth:1,
            'min-width':1,
            maxHeight:1,
            'max-height':1
        },
        uids = {},
        destroyer = document.createElement('div');

    function uid(type){
        if(!uids[type]){
            uids[type] = [];
        }
        var id = type + '-' + (uids[type].length + 1);
        uids[type].push(id);
        return id;
    }

    function isNode(item){
        // safer test for custom elements in FF (with wc shim)
        return typeof item === 'object' && typeof item.innerHTML === 'string';
    }

    function getNode(item){

        if(!item){ return item; }
        if(typeof item === 'string'){
            return document.getElementById(item);
        }
        // de-jqueryify
        return item.get ? item.get(0) :
            // item is a dom node
            item;
    }

    function byId(id){
        return getNode(id);
    }

    function style(node, prop, value){
        // get/set node style(s)
        //      prop: string or object
        //
        var key, computed;
        if(typeof prop === 'object'){
            // object setter
            for(key in prop){
                if(prop.hasOwnProperty(key)){
                    style(node, key, prop[key]);
                }
            }
            return null;
        }else if(value !== undefined){
            // property setter
            if(typeof value === 'number' && isDimension[prop]){
                value += 'px';
            }
            node.style[prop] = value;

            if(prop === 'userSelect'){
                value = !!value ? 'text' : 'none';
                style(node, {
                    webkitTouchCallout: value,
                    webkitUserSelect: value,
                    khtmlUserSelect: value,
                    mozUserSelect: value,
                    msUserSelect: value
                });
            }
        }

        // getter, if a simple style
        if(node.style[prop]){
            if(isDimension[prop]){
                return parseInt(node.style[prop], 10);
            }
            return node.style[prop];
        }

        // getter, computed
        computed = getComputedStyle(node, prop);
        if(computed[prop]){
            if(/\d/.test(computed[prop])){
                return parseInt(computed[prop], 10);
            }
            return computed[prop];
        }
        return '';
    }

    function attr(node, prop, value){
        // get/set node attribute(s)
        //      prop: string or object
        //
        var key;
        if(typeof prop === 'object'){
            for(key in prop){
                if(prop.hasOwnProperty(key)){
                    attr(node, key, prop[key]);
                }
            }
            return null;
        }
        else if(value !== undefined){
            if(prop === 'text' || prop === 'html' || prop === 'innerHTML'){
                node.innerHTML = value;
            }else{
                node.setAttribute(prop, value);
            }
        }

        return node.getAttribute(prop);
    }

    function box(node){
        if(node === window){
            return {
                width: node.innerWidth,
                height: node.innerHeight
            };
        }
        // node dimensions
        // returned object is immutable
        // add scroll positioning and convenience abbreviations
        var
            dimensions = getNode(node).getBoundingClientRect(),
            box = {
                top: dimensions.top,
                right: dimensions.right,
                bottom: dimensions.bottom,
                left: dimensions.left,
                height: dimensions.height,
                h: dimensions.height,
                width: dimensions.width,
                w: dimensions.width,
                scrollY: window.scrollY,
                scrollX: window.scrollX,
                x: dimensions.left + window.pageXOffset,
                y: dimensions.top + window.pageYOffset
            };

        return box;
    }

    function query(node, selector){
        if(!selector){
            selector = node;
            node = document;
        }
        var nodes = node.querySelectorAll(selector);

        // none found; return [] or null?
        if(!nodes.length){ return []; }

        // only one found, return single node
        if(nodes.length === 1){ return nodes[0];}

        // multiple found; convert to Array and return it
        return Array.prototype.slice.call(nodes);

    }

    function toDom(html, options, parent){
        // create a node from an HTML string
        var node = dom('div', {html: html});
        parent = byId(parent || options);
        if(parent){
            while(node.firstChild){
                parent.appendChild(node.firstChild);
            }
            return node.firstChild;
        }
        if(html.indexOf('<') !== 0){
            return node;
        }
        return node.firstChild;
    }

    function toFrag(html){
        var frag = document.createDocumentFragment();
        frag.innerHTML = html;
        return frag;
    }

    function dom(nodeType, options, parent, prepend){
        // create a node
        // if first argument is a string and starts with <, it is assumed
        // to use toDom, and creates a node from HTML. Optional second arg is
        // parent to append to
        // else:
        //      nodeType: string, type of node to create
        //      options: object with style, className, or attr properties
        //          (can also be objects)
        //      parent: Node, optional node to append to
        //      prepend: truthy, to append node as the first child
        //
        if(nodeType.indexOf('<') === 0){
            return toDom(nodeType, options, parent);
        }

        options = options || {};
        var
            className = options.css || options.className,
            node = document.createElement(nodeType);

        parent = getNode(parent);

        if(className){
            node.className = className;
        }

        if(options.html || options.innerHTML){
            node.innerHTML = options.html || options.innerHTML;
        }

        if(options.cssText){
            node.style.cssText = options.cssText;
        }

        if(options.id){
            node.id = options.id;
        }

        if(options.style){
            style(node, options.style);
        }

        if(options.attr){
            attr(node, options.attr);
        }

        if(parent && isNode(parent)){
            if(prepend && parent.hasChildNodes()){
                parent.insertBefore(node, parent.children[0]);
            }else{
                parent.appendChild(node);
            }
        }

        return node;
    }

    function destroy(node){
        // destroys a node completely
        //
        if(node) {
            destroyer.appendChild(node);
            destroyer.innerHTML = '';
        }
    }

    function clean(node, dispose){
        //	Removes all child nodes
        //		dispose: destroy child nodes
        if(dispose){
            while(node.children.length){
                destroy(node.children[0]);
            }
            return;
        }
        while(node.children.length){
            node.removeChild(node.children[0]);
        }
    }

    function ancestor (node, selector){
        // gets the ancestor of node based on selector criteria
        // useful for getting the target node when a child node is clicked upon
        //
        // USAGE
        //      on.selector(childNode, '.app.active');
        //      on.selector(childNode, '#thinger');
        //      on.selector(childNode, 'div');
        //	DOES NOT SUPPORT:
        //		combinations of above
        var
            test,
            parent = node;

        if(selector.indexOf('.') === 0){
            // className
            selector = selector.replace('.', ' ').trim();
            test = function(n){
                return n.classList.contains(selector);
            };
        }
        else if(selector.indexOf('#') === 0){
            // node id
            selector = selector.replace('#', '').trim();
            test = function(n){
                return n.id === selector;
            };
        }
        else if(selector.indexOf('[') > -1){
            // attribute
            console.error('attribute selectors are not yet supported');
        }
        else{
            // assuming node name
            selector = selector.toUpperCase();
            test = function(n){
                return n.nodeName === selector;
            };
        }

        while(parent){
            if(parent === document.body || parent === document){ return false; }
            if(test(parent)){ break; }
            parent = parent.parentNode;
        }

        return parent;
    }

    dom.classList = {
        remove: function(node, names){
            if(!node || !names){
                console.error('dom.classList.remove should include a node and a className');
                return;
            }
            names = Array.isArray(names) ? names : names.indexOf(' ') > -1 ? names.trim().split(' ') : [names];
            names.forEach(function(name){
                if(name){
                    node.classList.remove(name.trim());
                }
            });
        },
        add: function(node, names){
            if(!node || !names){
                return;
            }
            names = Array.isArray(names) ? names : names.indexOf(' ') > -1 ? names.trim().split(' ') : [names];
            names.forEach(function(name){
                if(name){
                    node.classList.add(name.trim());
                }
            });
        },
        contains: function(node, name){
            if(!node || !name){
                return false;
            }
            return node.classList.contains(name);
        },
        toggle: function(node, name){
            if(!node || !name){
                return null;
            }
            return node.classList.toggle(name);
        }
    };

    if (!window.requestAnimationFrame) {
        dom.requestAnimationFrame = function(callback){
            setTimeout(callback, 0);
        };
    }else{
        dom.requestAnimationFrame = function(cb){
            window.requestAnimationFrame(cb);
        };
    }

    dom.clean = clean;
    dom.query = query;
    dom.byId = byId;
    dom.attr = attr;
    dom.box = box;
    dom.style = style;
    dom.destroy = destroy;
    dom.uid = uid;
    dom.isNode = isNode;
    dom.ancestor = ancestor;
    dom.toDom = toDom;
    dom.toFrag = toFrag;

    return dom;
}));
<|endoftext|>


<commit_before>/**
 * Created by brian.hunter on 4/11/17.
 * Jest test file for testing creation, adjustment, and voiding of a transaction in the REST API
 */

/*Import sample data and expected responses*/
import Avatax from '../lib/AvaTaxClient';
import loadCreds from './helpers/load_creds';
import nock from 'nock';
import { account, licenseKey, companyCode } from './test_creds';
import transactionRequest from './fixtures/transaction_request';
import transactionResponse from './fixtures/transaction_response';
import adjustTransactionRequest from './fixtures/adjust_transaction_request';
import adjustTransactionResponse from './fixtures/adjust_transaction_response';
import voidTransactionRequest from './fixtures/void_transaction_request';
import voidTransactionResponse from './fixtures/void_transaction_response';

const transactionCode = transactionResponse.code;

const baseUrl = 'https://sandbox-rest.avatax.com';

describe.skip('Avatax Transactions', () => {
    const clientCreds = loadCreds();
    const client = new Avatax(clientCreds).withSecurity(clientCreds);

    describe('Creating new transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post('/api/v2/transactions/create', transactionRequest)
                .reply(201, transactionResponse);
        });

        it('should create a new transaction', () => {
            return client.createTransaction(transactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(transactionResponse);
                });
        });
    });

    /*Case for adjusting existing transaction
    *
    * Need to grab transactionCode from newly created transaction above
    * transactionCode = actualResponse.code;
    * EDIT - its hard coded in so we can cheat a little
    * */
    describe('Adjusting existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/adjust`, adjustTransactionRequest)
                .reply(200, adjustTransactionResponse);
        });

        it('should adjust an existing transaction', () => {
            return client.adjustTransaction(companyCode, transactionCode,adjustTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(adjustTransactionResponse);
                });
        });
    });

    /* Code for voiding an existing transaction
     *
     * Use same transactionCode from before
     * */
    describe('Voiding existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/void`, voidTransactionRequest)
                .reply(200, voidTransactionResponse);
        });

        it('should void an existing transaction', () => {
            return client.voidTransaction(companyCode, transactionCode, voidTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(voidTransactionResponse);
                });
        });
    });

});
<commit_msg>remove skip<commit_after>/**
 * Created by brian.hunter on 4/11/17.
 * Jest test file for testing creation, adjustment, and voiding of a transaction in the REST API
 */

/*Import sample data and expected responses*/
import Avatax from '../lib/AvaTaxClient';
import loadCreds from './helpers/load_creds';
import nock from 'nock';
import { account, licenseKey, companyCode } from './test_creds';
import transactionRequest from './fixtures/transaction_request';
import transactionResponse from './fixtures/transaction_response';
import adjustTransactionRequest from './fixtures/adjust_transaction_request';
import adjustTransactionResponse from './fixtures/adjust_transaction_response';
import voidTransactionRequest from './fixtures/void_transaction_request';
import voidTransactionResponse from './fixtures/void_transaction_response';

const transactionCode = transactionResponse.code;

const baseUrl = 'https://sandbox-rest.avatax.com';

describe('Avatax Transactions', () => {
    const clientCreds = loadCreds();
    const client = new Avatax(clientCreds).withSecurity(clientCreds);

    describe('Creating new transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post('/api/v2/transactions/create', transactionRequest)
                .reply(201, transactionResponse);
        });

        it('should create a new transaction', () => {
            return client.createTransaction(transactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(transactionResponse);
                });
        });
    });

    /*Case for adjusting existing transaction
    *
    * Need to grab transactionCode from newly created transaction above
    * transactionCode = actualResponse.code;
    * EDIT - its hard coded in so we can cheat a little
    * */
    describe('Adjusting existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/adjust`, adjustTransactionRequest)
                .reply(200, adjustTransactionResponse);
        });

        it('should adjust an existing transaction', () => {
            return client.adjustTransaction(companyCode, transactionCode,adjustTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(adjustTransactionResponse);
                });
        });
    });

    /* Code for voiding an existing transaction
     *
     * Use same transactionCode from before
     * */
    describe('Voiding existing transactions', () => {
        beforeEach(() => {
            nock(baseUrl)
                .post(`/api/v2/companies/${companyCode}/transactions/${transactionCode}/void`, voidTransactionRequest)
                .reply(200, voidTransactionResponse);
        });

        it('should void an existing transaction', () => {
            return client.voidTransaction(companyCode, transactionCode, voidTransactionRequest)
                .then(actualResponse => {
                    expect(actualResponse).toEqual(voidTransactionResponse);
                });
        });
    });

});
<|endoftext|>


<commit_before>var async = require('async');
var url = require('url');
var httpreq = require('httpreq');
var ntlm = require('./ntlm');

exports.get = function(options, callback){
	if(!options.workstation) options.workstation = '';
	if(!options.domain) options.domain = '';

	// is https?
	var isHttps = false;
	var reqUrl = url.parse(options.url);
	if(reqUrl.protocol == 'https:') isHttps = true;

	// set keepaliveAgent (http or https):
	var keepaliveAgent;

	if(isHttps){
		var HttpsAgent = require('agentkeepalive').HttpsAgent;
		keepaliveAgent = new HttpsAgent();
	}else{
		var Agent = require('agentkeepalive');
		keepaliveAgent = new Agent();
	}

	async.waterfall([
		function ($){
			var type1msg = ntlm.createType1Message(options);

			httpreq.get(options.url, {
				headers:{
					'Connection' : 'keep-alive',
					'Authorization': type1msg
				},
				agent: keepaliveAgent
			}, $);
		},

		function (res, $){
			if(!res.headers['www-authenticate'])
				return $(new Error('www-authenticate not found on response of second request'));

			var type2msg = ntlm.parseType2Message(res.headers['www-authenticate']);
			var type3msg = ntlm.createType3Message(type2msg, options);

			httpreq.get(options.url, {
				headers:{
					'Connection' : 'Close',
					'Authorization': type3msg
				},
				allowRedirects: false,
				agent: keepaliveAgent
			}, $);
		}
	], callback);
}

exports.ntlm = ntlm; //if you want to use the NTML functions yourself

<commit_msg>The client should support multiple http methods<commit_after>var async = require('async');
var url = require('url');
var httpreq = require('httpreq');
var ntlm = require('./ntlm');

exports.method = function(method, options, callback){
	if(!options.workstation) options.workstation = '';
	if(!options.domain) options.domain = '';

	// is https?
	var isHttps = false;
	var reqUrl = url.parse(options.url);
	if(reqUrl.protocol == 'https:') isHttps = true;

	// set keepaliveAgent (http or https):
	var keepaliveAgent;

	if(isHttps){
		var HttpsAgent = require('agentkeepalive').HttpsAgent;
		keepaliveAgent = new HttpsAgent();
	}else{
		var Agent = require('agentkeepalive');
		keepaliveAgent = new Agent();
	}

	async.waterfall([
		function ($){
			var type1msg = ntlm.createType1Message(options);

			httpreq.get(options.url, {
				headers:{
					'Connection' : 'keep-alive',
					'Authorization': type1msg
				},
				agent: keepaliveAgent
			}, $);
		},

		function (res, $){
			if(!res.headers['www-authenticate'])
				return $(new Error('www-authenticate not found on response of second request'));

			var type2msg = ntlm.parseType2Message(res.headers['www-authenticate']);
			var type3msg = ntlm.createType3Message(type2msg, options);

			httpreq[method](options.url, {
				headers:{
					'Connection' : 'Close',
					'Authorization': type3msg
				},
				allowRedirects: false,
				agent: keepaliveAgent
			}, $);
		}
	], callback);
};

['get', 'put', 'post', 'delete', 'head'].forEach(function(method){
  exports[method] = exports.method.bind(exports, method);
});

exports.ntlm = ntlm; //if you want to use the NTML functions yourself

<|endoftext|>


<commit_before>'use strict';

import chai, { expect } from 'chai';
import sinon from 'sinon';
import { default as sinonChai } from 'sinon-chai';
import Logger from 'browser/services/logger';
import Platform from 'browser/services/platform';
import ElectronMock from '../../../mock/electron';
<<<<<<< HEAD
import SelectionController from 'browser/pages/selection/controller';
=======
>>>>>>> 47b30f43f7d96075286ef7769eb73f413e45ad43

import fs from 'fs';

require('../../../angular-test-helper');
require('browser/main');

chai.use(sinonChai);

global.menu = {insert() {}};
global.MenuItem = function () {};
global.restoreMenu = function() {};

describe('SelectionController', function() {

  beforeEach(function() {
    sandbox.stub(Logger, 'getIpcRenderer').returns({send() {}});
  });

  afterEach(function() {
    sandbox.restore();
  });

  beforeEach(ngModule('devPlatInstaller'));

  let sandbox = sinon.sandbox.create();
  let electron = new ElectronMock();
  let $watch;
  let $controller;
  let $scope;
  let selectionController;
  let installerDataSvc;

  let context = function context(_$controller_, _$rootScope_, _$state_, _$timeout_, _installerDataSvc_) {
  // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
    $scope = _$rootScope_.$new();
    $scope.$apply = function applyStub() {};
    $watch = sandbox.spy($scope, '$watch');
    installerDataSvc = _installerDataSvc_;
    sandbox.stub(installerDataSvc, 'copyUninstaller');
    sandbox.stub(fs, 'existsSync').returns(true);
    sandbox.spy(_$state_, 'go');
    installerDataSvc.setup();

    selectionController = $controller('SelectionController', {
      $scope,
      $state: _$state_,
      $timeout: function timeoutStub(callback) { callback(); },
      installerDataSvc,
      electron
    });
    sandbox.spy(selectionController, 'setIsDisabled');
    for (let installer of installerDataSvc.allInstallables().values()) {
      sandbox.stub(installer, 'detectExistingInstall').resolves();
    }
  };

  describe('initial state', function() {
    describe('on all platforms', function() {
      beforeEach(inject(context));
      it('install watcher to track cdk selection to select its requirements', function() {
        expect($watch).to.be.calledWith('checkboxModel.cdk.selectedOption');
      });

      it('install watcher to track devstudio selection to select its requirements', function() {
        expect($watch).to.be.calledWith('checkboxModel.devstudio.selectedOption');
      });

      it('install watcher for $viewContentLoaded to trigger detection', function() {
        expect($watch).to.be.calledWith('$viewContentLoaded');
      });

      it('installs watchers to track components selected for install', function() {
        expect($watch.callCount).to.be.equal(selectionController.installerDataSvc.allInstallables().size+1);
      });

      it('unlock user interface after detection ends without errors', function() {
        return selectionController.initPage().then(function() {
          expect(selectionController.setIsDisabled).to.be.called;
        });
      });

      it('unlock user interface after detection ends with errors', function() {
        installerDataSvc.getInstallable('cdk').detectExistingInstall.rejects('error');
        return selectionController.initPage().then(function() {
          expect(selectionController.setIsDisabled).to.be.called;
        });
      });

      it('shows appropriate message when detection is in progress', function() {
        selectionController.initPage();
        expect(selectionController.installedSearchNote).includes('checking');
      });

      it('counts and present one detected component', function() {
        selectionController.sc.checkboxModel.kompose.selectedOption = 'detected';
        selectionController.sc.checkboxModel.kompose.option.detected = { valid: true };
        return selectionController.initPage().then(function() {
          expect(selectionController.numberOfExistingInstallations).equals(1);
          expect(selectionController.installedSearchNote).includes(' 1 ');
        });
      });

      it('counts and presents number of detected components', function() {
        selectionController.sc.checkboxModel.kompose.selectedOption = 'detected';
        selectionController.sc.checkboxModel.kompose.option.detected = { valid: true };
        selectionController.sc.checkboxModel.jdk.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jdk.option.detected = { valid: true };
        return selectionController.initPage().then(function() {
          expect(selectionController.numberOfExistingInstallations).equals(2);
          expect(selectionController.installedSearchNote).includes(' 2 ');
        });
      });
    });
  });

  describe('activatePage', function() {
    beforeEach(inject(context));
    it('unlock user interface after detection ends without errors', function() {
      return selectionController.activatePage().then(function() {
        expect(selectionController.setIsDisabled).to.be.called;
      });
    });

    it('unlock user interface after detection ends with errors', function() {
      installerDataSvc.getInstallable('cdk').detectExistingInstall.rejects('error');
      return selectionController.activatePage().then(function() {
        expect(selectionController.setIsDisabled).to.be.called;
      });
    });
  });

  describe('dependency resolution', function() {
    beforeEach(function() {
      sandbox.stub(Platform, 'getOS').returns('win32');
    });
    beforeEach(inject(context));
    it('should deselect openjdk if jbosseap and devstudio are not selected', function() {

      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('install');
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && (el[0] == 'checkboxModel.jbosseap.selectedOption'
            || el[0] == 'checkboxModel.devstudio.selectedOption'
            || el[0] == 'checkboxModel.fusetools.selectedOption')) {
            el[1]();
          }
        });
        selectionController.sc.checkboxModel.devstudio.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jbosseap.selectedOption = 'detected';
        selectionController.sc.checkboxModel.fusetools.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && (el[0] == 'checkboxModel.jbosseap.selectedOption'
            || el[0] == 'checkboxModel.devstudio.selectedOption'
            || el[0] == 'checkboxModel.fusetools.selectedOption')) {
            el[1]('detected', 'install');
          }
        });
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('detected');
      });
    });

    it('should select openjdk if jbosseap or devstudio selected', function() {
      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.devstudio.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.jbosseap.selectedOption).equals('detected');
        selectionController.sc.checkboxModel.jbosseap.selectedOption = 'install';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && ( el[0] == 'checkboxModel.jbosseap.selectedOption'
              || el[0] == 'checkboxModel.devstudio.selectedOption')) {
            el[1]('install', 'install'); // the same does angular avter initialization
          }
        });
        selectionController.sc.checkboxModel.devstudio.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jbosseap.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && ( el[0] == 'checkboxModel.jbosseap.selectedOption'
              || el[0] == 'checkboxModel.devstudio.selectedOption')) {
            el[1]('detected', 'install');
          }
        });
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('detected');

        selectionController.sc.checkboxModel.devstudio.selectedOption = 'install';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.devstudio.selectedOption') {
            el[1]('install', 'detected');
          }
        });
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('install');
      });
    });

    it('should deselect cygwin and virtualbox if cdk deselected', function() {
      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('install');
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]('install', 'detected');
          }
        });
        selectionController.sc.checkboxModel.cdk.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]('detected', 'install');
          }
        });
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('detected');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('detected');
      });
    });

    it('should select cygwin and virtualbox if cdk selected', function() {
      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.cdk.selectedOption).equals('install');
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && 'checkboxModel.cdk.selectedOption') {
            el[1]();
          }
        });
        selectionController.sc.checkboxModel.cdk.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]();
          }
        });

        selectionController.sc.checkboxModel.cdk.selectedOption = 'install';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]();
          }
        });
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('install');
      });
    });
  });

  describe('back', function() {
    beforeEach(function() {
      sandbox.stub(selectionController.router, 'go');
      selectionController.back();
    });

    it('navigates to location page', function() {
      expect(selectionController.router.go).calledWith('location');
    });
  });

  describe('exit', function() {
    it('exit closes active window', function() {
      sandbox.stub(electron.remote.currentWindow);
      selectionController.exit();
      expect(electron.remote.currentWindow.close).calledOnce;
    });
  });

  describe('isConfigurationValid', function() {
    it('should return true if all components selected for install are configured correctly', function() {
      //JDK on mac only is configured properly when detected with a valid version
      if (Platform.getOS() === 'darwin') {
        selectionController.sc.checkboxModel.jdk.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jdk.option.detected = { valid: true };
      }
      selectionController.sc.checkboxModel.kompose.selectedOption = 'detected';

      expect(selectionController.isConfigurationValid()).to.be.true;
    });

    it('should return false if nothing is selected for installation', function() {
      for (var installer of installerDataSvc.allInstallables().values()) {
        sandbox.stub(installer, 'isSkipped').returns(true);
      }
      expect(selectionController.isConfigurationValid()).to.be.false;
    });

    it('should return false if at least one component selected for installation is not configured correctly', function() {
      let cdk = selectionController.installerDataSvc.getInstallable('cdk');
      sandbox.stub(cdk, 'isConfigurationValid').returns(false);
      expect(selectionController.isConfigurationValid()).to.be.false;
    });
  });

  describe('download', function() {
    it('should open url in browser using electron.shell.openExternal', function() {
      sandbox.stub(electron.shell);
      selectionController.download('url');
      expect(electron.shell.openExternal).calledOnce;
    });
  });

  describe('detectInstalledComponents', function() {
    it('should return existing promise if detection is already running', function() {
      let detection = selectionController.detectInstalledComponents();
      expect(detection).equals(selectionController.detectInstalledComponents());
    });
  });

  describe('selectAll', function() {
    beforeEach(inject(context));
    it('should not select detected components', function() {
      let kompose = selectionController.sc.checkboxModel.kompose;
      kompose.addOption('detected', '1.0.0', 'location', true);
      kompose.selectedOption = 'detected';
      selectionController.selectAll();
      expect(kompose.selectedOption).equals('detected');
    });

    it('should select all installable components', function() {
      let kompose = selectionController.sc.checkboxModel.kompose;
      selectionController.selectAll();
      expect(kompose.selectedOption).equals('install');
    });
  });

  describe('deselectAll', function() {
    beforeEach(inject(context));
    it('should deselect all detected components', function() {
      selectionController.deselectAll();
      for (let installer of installerDataSvc.allInstallables().values()) {
        expect(installer.selectedOption).equals('detected');
      }
    });
  });
});
<commit_msg>fix merge conflicts<commit_after>'use strict';

import chai, { expect } from 'chai';
import sinon from 'sinon';
import { default as sinonChai } from 'sinon-chai';
import Logger from 'browser/services/logger';
import Platform from 'browser/services/platform';
import ElectronMock from '../../../mock/electron';

import fs from 'fs';

require('../../../angular-test-helper');
require('browser/main');

chai.use(sinonChai);

global.menu = {insert() {}};
global.MenuItem = function () {};
global.restoreMenu = function() {};

describe('SelectionController', function() {

  beforeEach(function() {
    sandbox.stub(Logger, 'getIpcRenderer').returns({send() {}});
  });

  afterEach(function() {
    sandbox.restore();
  });

  beforeEach(ngModule('devPlatInstaller'));

  let sandbox = sinon.sandbox.create();
  let electron = new ElectronMock();
  let $watch;
  let $controller;
  let $scope;
  let selectionController;
  let installerDataSvc;

  let context = function context(_$controller_, _$rootScope_, _$state_, _$timeout_, _installerDataSvc_) {
  // The injector unwraps the underscores (_) from around the parameter names when matching
    $controller = _$controller_;
    $scope = _$rootScope_.$new();
    $scope.$apply = function applyStub() {};
    $watch = sandbox.spy($scope, '$watch');
    installerDataSvc = _installerDataSvc_;
    sandbox.stub(installerDataSvc, 'copyUninstaller');
    sandbox.stub(fs, 'existsSync').returns(true);
    sandbox.spy(_$state_, 'go');
    installerDataSvc.setup();

    selectionController = $controller('SelectionController', {
      $scope,
      $state: _$state_,
      $timeout: function timeoutStub(callback) { callback(); },
      installerDataSvc,
      electron
    });
    sandbox.spy(selectionController, 'setIsDisabled');
    for (let installer of installerDataSvc.allInstallables().values()) {
      sandbox.stub(installer, 'detectExistingInstall').resolves();
    }
  };

  describe('initial state', function() {
    describe('on all platforms', function() {
      beforeEach(inject(context));
      it('install watcher to track cdk selection to select its requirements', function() {
        expect($watch).to.be.calledWith('checkboxModel.cdk.selectedOption');
      });

      it('install watcher to track devstudio selection to select its requirements', function() {
        expect($watch).to.be.calledWith('checkboxModel.devstudio.selectedOption');
      });

      it('install watcher for $viewContentLoaded to trigger detection', function() {
        expect($watch).to.be.calledWith('$viewContentLoaded');
      });

      it('installs watchers to track components selected for install', function() {
        expect($watch.callCount).to.be.equal(selectionController.installerDataSvc.allInstallables().size+1);
      });

      it('unlock user interface after detection ends without errors', function() {
        return selectionController.initPage().then(function() {
          expect(selectionController.setIsDisabled).to.be.called;
        });
      });

      it('unlock user interface after detection ends with errors', function() {
        installerDataSvc.getInstallable('cdk').detectExistingInstall.rejects('error');
        return selectionController.initPage().then(function() {
          expect(selectionController.setIsDisabled).to.be.called;
        });
      });

      it('shows appropriate message when detection is in progress', function() {
        selectionController.initPage();
        expect(selectionController.installedSearchNote).includes('checking');
      });

      it('counts and present one detected component', function() {
        selectionController.sc.checkboxModel.kompose.selectedOption = 'detected';
        selectionController.sc.checkboxModel.kompose.option.detected = { valid: true };
        return selectionController.initPage().then(function() {
          expect(selectionController.numberOfExistingInstallations).equals(1);
          expect(selectionController.installedSearchNote).includes(' 1 ');
        });
      });

      it('counts and presents number of detected components', function() {
        selectionController.sc.checkboxModel.kompose.selectedOption = 'detected';
        selectionController.sc.checkboxModel.kompose.option.detected = { valid: true };
        selectionController.sc.checkboxModel.jdk.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jdk.option.detected = { valid: true };
        return selectionController.initPage().then(function() {
          expect(selectionController.numberOfExistingInstallations).equals(2);
          expect(selectionController.installedSearchNote).includes(' 2 ');
        });
      });
    });
  });

  describe('activatePage', function() {
    beforeEach(inject(context));
    it('unlock user interface after detection ends without errors', function() {
      return selectionController.activatePage().then(function() {
        expect(selectionController.setIsDisabled).to.be.called;
      });
    });

    it('unlock user interface after detection ends with errors', function() {
      installerDataSvc.getInstallable('cdk').detectExistingInstall.rejects('error');
      return selectionController.activatePage().then(function() {
        expect(selectionController.setIsDisabled).to.be.called;
      });
    });
  });

  describe('dependency resolution', function() {
    beforeEach(function() {
      sandbox.stub(Platform, 'getOS').returns('win32');
    });
    beforeEach(inject(context));
    it('should deselect openjdk if jbosseap and devstudio are not selected', function() {

      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('install');
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && (el[0] == 'checkboxModel.jbosseap.selectedOption'
            || el[0] == 'checkboxModel.devstudio.selectedOption'
            || el[0] == 'checkboxModel.fusetools.selectedOption')) {
            el[1]();
          }
        });
        selectionController.sc.checkboxModel.devstudio.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jbosseap.selectedOption = 'detected';
        selectionController.sc.checkboxModel.fusetools.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && (el[0] == 'checkboxModel.jbosseap.selectedOption'
            || el[0] == 'checkboxModel.devstudio.selectedOption'
            || el[0] == 'checkboxModel.fusetools.selectedOption')) {
            el[1]('detected', 'install');
          }
        });
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('detected');
      });
    });

    it('should select openjdk if jbosseap or devstudio selected', function() {
      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.devstudio.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.jbosseap.selectedOption).equals('detected');
        selectionController.sc.checkboxModel.jbosseap.selectedOption = 'install';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && ( el[0] == 'checkboxModel.jbosseap.selectedOption'
              || el[0] == 'checkboxModel.devstudio.selectedOption')) {
            el[1]('install', 'install'); // the same does angular avter initialization
          }
        });
        selectionController.sc.checkboxModel.devstudio.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jbosseap.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && ( el[0] == 'checkboxModel.jbosseap.selectedOption'
              || el[0] == 'checkboxModel.devstudio.selectedOption')) {
            el[1]('detected', 'install');
          }
        });
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('detected');

        selectionController.sc.checkboxModel.devstudio.selectedOption = 'install';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.devstudio.selectedOption') {
            el[1]('install', 'detected');
          }
        });
        expect(selectionController.sc.checkboxModel.jdk.selectedOption).equals('install');
      });
    });

    it('should deselect cygwin and virtualbox if cdk deselected', function() {
      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('install');
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]('install', 'detected');
          }
        });
        selectionController.sc.checkboxModel.cdk.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]('detected', 'install');
          }
        });
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('detected');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('detected');
      });
    });

    it('should select cygwin and virtualbox if cdk selected', function() {
      return selectionController.initPage().then(function() {
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.cdk.selectedOption).equals('install');
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && 'checkboxModel.cdk.selectedOption') {
            el[1]();
          }
        });
        selectionController.sc.checkboxModel.cdk.selectedOption = 'detected';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]();
          }
        });

        selectionController.sc.checkboxModel.cdk.selectedOption = 'install';
        $watch.args.forEach(function(el) {
          if(el[1].name == 'watchComponent'
            && el[0] == 'checkboxModel.cdk.selectedOption') {
            el[1]();
          }
        });
        expect(selectionController.sc.checkboxModel.cygwin.selectedOption).equals('install');
        expect(selectionController.sc.checkboxModel.virtualbox.selectedOption).equals('install');
      });
    });
  });

  describe('back', function() {
    beforeEach(function() {
      sandbox.stub(selectionController.router, 'go');
      selectionController.back();
    });

    it('navigates to location page', function() {
      expect(selectionController.router.go).calledWith('location');
    });
  });

  describe('exit', function() {
    it('exit closes active window', function() {
      sandbox.stub(electron.remote.currentWindow);
      selectionController.exit();
      expect(electron.remote.currentWindow.close).calledOnce;
    });
  });

  describe('isConfigurationValid', function() {
    it('should return true if all components selected for install are configured correctly', function() {
      //JDK on mac only is configured properly when detected with a valid version
      if (Platform.getOS() === 'darwin') {
        selectionController.sc.checkboxModel.jdk.selectedOption = 'detected';
        selectionController.sc.checkboxModel.jdk.option.detected = { valid: true };
      }
      selectionController.sc.checkboxModel.kompose.selectedOption = 'detected';

      expect(selectionController.isConfigurationValid()).to.be.true;
    });

    it('should return false if nothing is selected for installation', function() {
      for (var installer of installerDataSvc.allInstallables().values()) {
        sandbox.stub(installer, 'isSkipped').returns(true);
      }
      expect(selectionController.isConfigurationValid()).to.be.false;
    });

    it('should return false if at least one component selected for installation is not configured correctly', function() {
      let cdk = selectionController.installerDataSvc.getInstallable('cdk');
      sandbox.stub(cdk, 'isConfigurationValid').returns(false);
      expect(selectionController.isConfigurationValid()).to.be.false;
    });
  });

  describe('download', function() {
    it('should open url in browser using electron.shell.openExternal', function() {
      sandbox.stub(electron.shell);
      selectionController.download('url');
      expect(electron.shell.openExternal).calledOnce;
    });
  });

  describe('detectInstalledComponents', function() {
    it('should return existing promise if detection is already running', function() {
      let detection = selectionController.detectInstalledComponents();
      expect(detection).equals(selectionController.detectInstalledComponents());
    });
  });

  describe('selectAll', function() {
    beforeEach(inject(context));
    it('should not select detected components', function() {
      let kompose = selectionController.sc.checkboxModel.kompose;
      kompose.addOption('detected', '1.0.0', 'location', true);
      kompose.selectedOption = 'detected';
      selectionController.selectAll();
      expect(kompose.selectedOption).equals('detected');
    });

    it('should select all installable components', function() {
      let kompose = selectionController.sc.checkboxModel.kompose;
      selectionController.selectAll();
      expect(kompose.selectedOption).equals('install');
    });
  });

  describe('deselectAll', function() {
    beforeEach(inject(context));
    it('should deselect all detected components', function() {
      selectionController.deselectAll();
      for (let installer of installerDataSvc.allInstallables().values()) {
        expect(installer.selectedOption).equals('detected');
      }
    });
  });
});
<|endoftext|>