<commit_before>const childProcess = require('child_process')
const fs = require('fs')
const path = require('path')
const electronLink = require('electron-link')
const terser = require('terser')
const CONFIG = require('../config')

module.exports = function (packagedAppPath) {
  const snapshotScriptPath = path.join(CONFIG.buildOutputPath, 'startup.js')
  const coreModules = new Set(['electron', 'atom', 'shell', 'WNdb', 'lapack', 'remote'])
  const baseDirPath = path.join(CONFIG.intermediateAppPath, 'static')
  let processedFiles = 0

  return electronLink({
    baseDirPath,
    mainPath: path.resolve(baseDirPath, '..', 'src', 'initialize-application-window.js'),
    cachePath: path.join(CONFIG.atomHomeDirPath, 'snapshot-cache'),
    auxiliaryData: CONFIG.snapshotAuxiliaryData,
    shouldExcludeModule: ({requiringModulePath, requiredModulePath}) => {
      if (processedFiles > 0) {
        process.stdout.write('\r')
      }
      process.stdout.write(`Generating snapshot script at "${snapshotScriptPath}" (${++processedFiles})`)

      const requiringModuleRelativePath = path.relative(baseDirPath, requiringModulePath)
      const requiredModuleRelativePath = path.relative(baseDirPath, requiredModulePath)
      return (
        requiredModulePath.endsWith('.node') ||
        coreModules.has(requiredModulePath) ||
        requiringModuleRelativePath.endsWith(path.join('node_modules/xregexp/xregexp-all.js')) ||
        (requiredModuleRelativePath.startsWith(path.join('..', 'src')) && requiredModuleRelativePath.endsWith('-element.js')) ||
        requiredModuleRelativePath.startsWith(path.join('..', 'node_modules', 'dugite')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'coffee-script', 'lib', 'coffee-script', 'register.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'fs-extra', 'lib', 'index.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'graceful-fs', 'graceful-fs.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'htmlparser2', 'lib', 'index.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'minimatch', 'minimatch.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'request', 'index.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'request', 'request.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'temp', 'lib', 'temp.js')) ||
        requiredModuleRelativePath === path.join('..', 'exports', 'atom.js') ||
        requiredModuleRelativePath === path.join('..', 'src', 'electron-shims.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'atom-keymap', 'lib', 'command-event.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'babel-core', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'cached-run-in-this-context', 'lib', 'main.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'debug', 'node.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'git-utils', 'src', 'git.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'glob', 'glob.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'iconv-lite', 'lib', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'less', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'less', 'lib', 'less', 'fs.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'less', 'lib', 'less-node', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'lodash.isequal', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'node-fetch', 'lib', 'fetch-error.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'superstring', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'oniguruma', 'src', 'oniguruma.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'resolve', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'resolve', 'lib', 'core.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'settings-view', 'node_modules', 'glob', 'glob.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'spellchecker', 'lib', 'spellchecker.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'spelling-manager', 'node_modules', 'natural', 'lib', 'natural', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'tar', 'tar.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'ls-archive', 'node_modules', 'tar', 'tar.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'tmp', 'lib', 'tmp.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'tree-sitter', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'yauzl', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'winreg', 'lib', 'registry.js')
      )
    }
  }).then(({snapshotScript}) => {
    process.stdout.write('\n')

    process.stdout.write('Minifying startup script')
    const minification = terser.minify(snapshotScript, {
      keep_fnames: true,
      keep_classnames: true,
      compress: {keep_fargs: true, keep_infinity: true}
    })
    if (minification.error) throw minification.error
    process.stdout.write('\n')
    fs.writeFileSync(snapshotScriptPath, minification.code)

    console.log('Verifying if snapshot can be executed via `mksnapshot`')
    const verifySnapshotScriptPath = path.join(CONFIG.repositoryRootPath, 'script', 'verify-snapshot-script')
    let nodeBundledInElectronPath
    if (process.platform === 'darwin') {
      const executableName = CONFIG.appName
      nodeBundledInElectronPath = path.join(packagedAppPath, 'Contents', 'MacOS', executableName)
    } else if (process.platform === 'win32') {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom.exe')
    } else {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom')
    }
    childProcess.execFileSync(
      nodeBundledInElectronPath,
      [verifySnapshotScriptPath, snapshotScriptPath],
      {env: Object.assign({}, process.env, {ELECTRON_RUN_AS_NODE: 1})}
    )

    const generatedStartupBlobPath = path.join(CONFIG.buildOutputPath, 'snapshot_blob.bin')
    console.log(`Generating startup blob at "${generatedStartupBlobPath}"`)
    childProcess.execFileSync(
      path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'bin', 'mksnapshot'),
      ['--no-use_ic', snapshotScriptPath, '--startup_blob', generatedStartupBlobPath]
    )

    let startupBlobDestinationPath
    if (process.platform === 'darwin') {
      startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources/snapshot_blob.bin`
    } else {
      startupBlobDestinationPath = path.join(packagedAppPath, 'snapshot_blob.bin')
    }

    console.log(`Moving generated startup blob into "${startupBlobDestinationPath}"`)
    fs.unlinkSync(startupBlobDestinationPath)
    fs.renameSync(generatedStartupBlobPath, startupBlobDestinationPath)
  })
}
<commit_msg>Update snapshot path from snapshot_blob to v8_context_snapshot<commit_after>const childProcess = require('child_process')
const fs = require('fs')
const path = require('path')
const electronLink = require('electron-link')
const terser = require('terser')
const CONFIG = require('../config')

module.exports = function (packagedAppPath) {
  const snapshotScriptPath = path.join(CONFIG.buildOutputPath, 'startup.js')
  const coreModules = new Set(['electron', 'atom', 'shell', 'WNdb', 'lapack', 'remote'])
  const baseDirPath = path.join(CONFIG.intermediateAppPath, 'static')
  let processedFiles = 0

  return electronLink({
    baseDirPath,
    mainPath: path.resolve(baseDirPath, '..', 'src', 'initialize-application-window.js'),
    cachePath: path.join(CONFIG.atomHomeDirPath, 'snapshot-cache'),
    auxiliaryData: CONFIG.snapshotAuxiliaryData,
    shouldExcludeModule: ({requiringModulePath, requiredModulePath}) => {
      if (processedFiles > 0) {
        process.stdout.write('\r')
      }
      process.stdout.write(`Generating snapshot script at "${snapshotScriptPath}" (${++processedFiles})`)

      const requiringModuleRelativePath = path.relative(baseDirPath, requiringModulePath)
      const requiredModuleRelativePath = path.relative(baseDirPath, requiredModulePath)
      return (
        requiredModulePath.endsWith('.node') ||
        coreModules.has(requiredModulePath) ||
        requiringModuleRelativePath.endsWith(path.join('node_modules/xregexp/xregexp-all.js')) ||
        (requiredModuleRelativePath.startsWith(path.join('..', 'src')) && requiredModuleRelativePath.endsWith('-element.js')) ||
        requiredModuleRelativePath.startsWith(path.join('..', 'node_modules', 'dugite')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'coffee-script', 'lib', 'coffee-script', 'register.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'fs-extra', 'lib', 'index.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'graceful-fs', 'graceful-fs.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'htmlparser2', 'lib', 'index.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'minimatch', 'minimatch.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'request', 'index.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'request', 'request.js')) ||
        requiredModuleRelativePath.endsWith(path.join('node_modules', 'temp', 'lib', 'temp.js')) ||
        requiredModuleRelativePath === path.join('..', 'exports', 'atom.js') ||
        requiredModuleRelativePath === path.join('..', 'src', 'electron-shims.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'atom-keymap', 'lib', 'command-event.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'babel-core', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'cached-run-in-this-context', 'lib', 'main.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'debug', 'node.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'git-utils', 'src', 'git.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'glob', 'glob.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'iconv-lite', 'lib', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'less', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'less', 'lib', 'less', 'fs.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'less', 'lib', 'less-node', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'lodash.isequal', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'node-fetch', 'lib', 'fetch-error.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'superstring', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'oniguruma', 'src', 'oniguruma.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'resolve', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'resolve', 'lib', 'core.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'settings-view', 'node_modules', 'glob', 'glob.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'spellchecker', 'lib', 'spellchecker.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'spelling-manager', 'node_modules', 'natural', 'lib', 'natural', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'tar', 'tar.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'ls-archive', 'node_modules', 'tar', 'tar.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'tmp', 'lib', 'tmp.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'tree-sitter', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'yauzl', 'index.js') ||
        requiredModuleRelativePath === path.join('..', 'node_modules', 'winreg', 'lib', 'registry.js')
      )
    }
  }).then(({snapshotScript}) => {
    process.stdout.write('\n')

    process.stdout.write('Minifying startup script')
    const minification = terser.minify(snapshotScript, {
      keep_fnames: true,
      keep_classnames: true,
      compress: {keep_fargs: true, keep_infinity: true}
    })
    if (minification.error) throw minification.error
    process.stdout.write('\n')
    fs.writeFileSync(snapshotScriptPath, minification.code)

    console.log('Verifying if snapshot can be executed via `mksnapshot`')
    const verifySnapshotScriptPath = path.join(CONFIG.repositoryRootPath, 'script', 'verify-snapshot-script')
    let nodeBundledInElectronPath
    if (process.platform === 'darwin') {
      const executableName = CONFIG.appName
      nodeBundledInElectronPath = path.join(packagedAppPath, 'Contents', 'MacOS', executableName)
    } else if (process.platform === 'win32') {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom.exe')
    } else {
      nodeBundledInElectronPath = path.join(packagedAppPath, 'atom')
    }
    childProcess.execFileSync(
      nodeBundledInElectronPath,
      [verifySnapshotScriptPath, snapshotScriptPath],
      {env: Object.assign({}, process.env, {ELECTRON_RUN_AS_NODE: 1})}
    )

    const generatedStartupBlobPath = path.join(CONFIG.buildOutputPath, 'v8_context_snapshot.bin')
    console.log(`Generating startup blob at "${generatedStartupBlobPath}"`)
    childProcess.execFileSync(
      path.join(CONFIG.repositoryRootPath, 'script', 'node_modules', 'electron-mksnapshot', 'bin', 'mksnapshot'),
      ['--no-use_ic', snapshotScriptPath, '--startup_blob', generatedStartupBlobPath]
    )

    let startupBlobDestinationPath
    if (process.platform === 'darwin') {
      startupBlobDestinationPath = `${packagedAppPath}/Contents/Frameworks/Electron Framework.framework/Resources/v8_context_snapshot.bin`
    } else {
      startupBlobDestinationPath = path.join(packagedAppPath, 'v8_context_snapshot.bin')
    }

    console.log(`Moving generated startup blob into "${startupBlobDestinationPath}"`)
    fs.unlinkSync(startupBlobDestinationPath)
    fs.renameSync(generatedStartupBlobPath, startupBlobDestinationPath)
  })
}
<|endoftext|>


<commit_before>import React from 'react'
import toClassNames from 'classnames'

const BLOCK_NAME = 'fui-Component'
const WORD_WITH_COLON_PREFIX = /(:[^\s]+)/
const WORD_WITHOUT_COLON_PREFIX = /^(?!:).+/

export default class Component extends React.Component {

  static propTypes = {
    as: React.PropTypes.any
  }

  static defaultProps = {
    as: 'div'
  }

  render () {
    const localProps = this.props
    const remoteProps = this.props.props || {}

    let {blockName, additionalClasses} = classNameDetailsOf({
      localClassName: localProps.className,
      remoteClassName: remoteProps.className,
      conditionalClassNames: [
        localProps.classes,
        remoteProps.classes
      ]
    })

    const modifiers = getModsFor({
      blockName,
      modifiers: remoteProps.kind,
      match: WORD_WITHOUT_COLON_PREFIX
    })

    const rootBlockModifiers = getModsFor({
      blockName: BLOCK_NAME,
      modifiers: remoteProps.kind,
      match: WORD_WITH_COLON_PREFIX
    })

    const className = cleanClassNames(
      `${BLOCK_NAME} ${blockName} ${modifiers} ${additionalClasses} ${rootBlockModifiers}`
    )

    const tag = remoteProps.as || this.props.as

    const props = {}

    const attributesNotToPassThrough = [
      'as',
      'className',
      '_reactInternalInstance',
      'updater',
      'refs',
      'context',
      'props'
    ]

    Object.keys(localProps).forEach((key) => {
      if (key.startsWith('data-') || ![attributesNotToPassThrough].includes(key)) {
        props[key] = this.props[key]
      }
    })

    props.className = className

    return React.createElement(tag, props, this.props.children)
  }
}

function classNameDetailsOf ({localClassName, remoteClassName, conditionalClassNames}) {
  const localNames = typeof localClassName === 'string'
    ? localClassName.split(' ')
    : []

  const additionalLocalClassNames = localNames.length > 1
    ? localNames.splice(1, localNames.length).join(' ')
    : ''

  const additionalRemoteClassNames = remoteClassName === undefined
    ? ''
    : remoteClassName

  return {
    blockName: localNames[0] || '',
    additionalClasses: `${additionalRemoteClassNames} ${additionalLocalClassNames} ${toClassNames(conditionalClassNames)}`
  }
}

function cleanClassNames (classNames) {
  return removeExtraSpacesFromCssClassNames(
    removeDuplicatesFromCssClassNames(classNames)
  )
}

function removeDuplicatesFromCssClassNames (value) {
  const obj = {}
  value.split(' ').forEach(item => {
    obj[item] = ''
  })
  return Object.keys(obj).join(' ')
}

function removeExtraSpacesFromCssClassNames (classes) {
  return classes.replace('  ', ' ').trim()
}

function getModsFor ({blockName, modifiers, match}) {

  const mods = []

  if (modifiers) {
    for (let modifier of modifiers.split(' ')) {
      if (match.test(modifier)) {
        mods.push(`${blockName}--${modifier.replace(':', '')}`)
      }
    }
  }

  return mods.join(' ')
}
<commit_msg>pass props through except `as`, `className`, and `props`<commit_after>import React from 'react'
import toClassNames from 'classnames'

const BLOCK_NAME = 'fui-Component'
const WORD_WITH_COLON_PREFIX = /(:[^\s]+)/
const WORD_WITHOUT_COLON_PREFIX = /^(?!:).+/

export default class Component extends React.Component {

  static propTypes = {
    as: React.PropTypes.any
  }

  static defaultProps = {
    as: 'div'
  }

  render () {
    const localProps = this.props
    const remoteProps = this.props.props || {}

    let {blockName, additionalClasses} = classNameDetailsOf({
      localClassName: localProps.className,
      remoteClassName: remoteProps.className,
      conditionalClassNames: [
        localProps.classes,
        remoteProps.classes
      ]
    })

    const modifiers = getModsFor({
      blockName,
      modifiers: remoteProps.kind,
      match: WORD_WITHOUT_COLON_PREFIX
    })

    const rootBlockModifiers = getModsFor({
      blockName: BLOCK_NAME,
      modifiers: remoteProps.kind,
      match: WORD_WITH_COLON_PREFIX
    })

    const className = cleanClassNames(
      `${BLOCK_NAME} ${blockName} ${modifiers} ${additionalClasses} ${rootBlockModifiers}`
    )

    const tag = remoteProps.as || this.props.as

    const props = {}

    const attributesNotToPassThrough = [
      'as',
      'className',
      'props'
    ]

    Object.keys(localProps).forEach((key) => {
      if (key.startsWith('data-') || !attributesNotToPassThrough.includes(key)) {
        props[key] = this.props[key]
      }
    })

    props.className = className

    return React.createElement(tag, props, this.props.children)
  }
}

function classNameDetailsOf ({localClassName, remoteClassName, conditionalClassNames}) {
  const localNames = typeof localClassName === 'string'
    ? localClassName.split(' ')
    : []

  const additionalLocalClassNames = localNames.length > 1
    ? localNames.splice(1, localNames.length).join(' ')
    : ''

  const additionalRemoteClassNames = remoteClassName === undefined
    ? ''
    : remoteClassName

  return {
    blockName: localNames[0] || '',
    additionalClasses: `${additionalRemoteClassNames} ${additionalLocalClassNames} ${toClassNames(conditionalClassNames)}`
  }
}

function cleanClassNames (classNames) {
  return removeExtraSpacesFromCssClassNames(
    removeDuplicatesFromCssClassNames(classNames)
  )
}

function removeDuplicatesFromCssClassNames (value) {
  const obj = {}
  value.split(' ').forEach(item => {
    obj[item] = ''
  })
  return Object.keys(obj).join(' ')
}

function removeExtraSpacesFromCssClassNames (classes) {
  return classes.replace('  ', ' ').trim()
}

function getModsFor ({blockName, modifiers, match}) {

  const mods = []

  if (modifiers) {
    for (let modifier of modifiers.split(' ')) {
      if (match.test(modifier)) {
        mods.push(`${blockName}--${modifier.replace(':', '')}`)
      }
    }
  }

  return mods.join(' ')
}
<|endoftext|>


<commit_before>// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
 * @unrestricted
 */
Emulation.DeviceModeWrapper = class extends UI.VBox {
  /**
   * @param {!Emulation.InspectedPagePlaceholder} inspectedPagePlaceholder
   */
  constructor(inspectedPagePlaceholder) {
    super();
    Emulation.DeviceModeView._wrapperInstance = this;
    this._inspectedPagePlaceholder = inspectedPagePlaceholder;
    /** @type {?Emulation.DeviceModeView} */
    this._deviceModeView = null;
    this._toggleDeviceModeAction = UI.actionRegistry.action('emulation.toggle-device-mode');
    const model = self.singleton(Emulation.DeviceModeModel);
    this._showDeviceModeSetting = model.enabledSetting();
    this._showDeviceModeSetting.setRequiresUserAction(!!Runtime.queryParam('hasOtherClients'));
    this._showDeviceModeSetting.addChangeListener(this._update.bind(this, false));
    SDK.targetManager.addModelListener(
        SDK.OverlayModel, SDK.OverlayModel.Events.ScreenshotRequested, this._screenshotRequestedFromOverlay, this);
    this._update(true);
  }

  _toggleDeviceMode() {
    this._showDeviceModeSetting.set(!this._showDeviceModeSetting.get());
  }

  /**
   * @param {boolean=} fullSize
   * @param {!Protocol.Page.Viewport=} clip
   * @return {boolean}
   */
  _captureScreenshot(fullSize, clip) {
    if (!this._deviceModeView)
      this._deviceModeView = new Emulation.DeviceModeView();
    this._deviceModeView.setNonEmulatedAvailableSize(this._inspectedPagePlaceholder.element);
    if (fullSize)
      this._deviceModeView.captureFullSizeScreenshot();
    else if (clip)
      this._deviceModeView.captureAreaScreenshot(clip);
    else
      this._deviceModeView.captureScreenshot();
    return true;
  }

  /**
   * @param {!Common.Event} event
   */
  _screenshotRequestedFromOverlay(event) {
    const clip = /** @type {!Protocol.Page.Viewport} */ (event.data);
    this._captureScreenshot(false, clip);
  }

  /**
   * @param {boolean} force
   */
  _update(force) {
    this._toggleDeviceModeAction.setToggled(this._showDeviceModeSetting.get());
    if (!force) {
      const showing = this._deviceModeView && this._deviceModeView.isShowing();
      if (this._showDeviceModeSetting.get() === showing)
        return;
    }

    if (this._showDeviceModeSetting.get()) {
      if (!this._deviceModeView)
        this._deviceModeView = new Emulation.DeviceModeView();
      this._deviceModeView.show(this.element);
      this._inspectedPagePlaceholder.clearMinimumSize();
      this._inspectedPagePlaceholder.show(this._deviceModeView.element);
    } else {
      if (this._deviceModeView)
        this._deviceModeView.detach();
      this._inspectedPagePlaceholder.restoreMinimumSize();
      this._inspectedPagePlaceholder.show(this.element);
    }
  }
};

/** @type {!Emulation.DeviceModeWrapper} */
Emulation.DeviceModeView._wrapperInstance;

/**
 * @implements {UI.ActionDelegate}
 * @unrestricted
 */
Emulation.DeviceModeWrapper.ActionDelegate = class {
  /**
   * @override
   * @param {!UI.Context} context
   * @param {string} actionId
   * @return {boolean}
   */
  handleAction(context, actionId) {
    if (Emulation.DeviceModeView._wrapperInstance) {
      switch (actionId) {
        case 'emulation.capture-screenshot':
          return Emulation.DeviceModeView._wrapperInstance._captureScreenshot();

        case 'emulation.capture-node-screenshot': {
          const node = UI.context.flavor(SDK.DOMNode);
          if (!node)
            return true;
          async function captureClip() {
            const object = await node.resolveToObject();
            const result = await object.callFunction(function() {
              const rect = this.getBoundingClientRect();
              const docRect = this.ownerDocument.documentElement.getBoundingClientRect();
              return JSON.stringify({
                x: rect.left - docRect.left,
                y: rect.top - docRect.top,
                width: rect.width,
                height: rect.height,
                scale: 1
              });
            });
            const clip = /** @type {!Protocol.Page.Viewport} */ (JSON.parse(result.object.value));
            Emulation.DeviceModeView._wrapperInstance._captureScreenshot(false, clip);
          }
          captureClip();
          return true;
        }

        case 'emulation.capture-full-height-screenshot':
          return Emulation.DeviceModeView._wrapperInstance._captureScreenshot(true);

        case 'emulation.toggle-device-mode':
          Emulation.DeviceModeView._wrapperInstance._toggleDeviceMode();
          return true;
      }
    }
    return false;
  }
};
<commit_msg>DevTools: Make node screenshot pass coordinates in dip.<commit_after>// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
 * @unrestricted
 */
Emulation.DeviceModeWrapper = class extends UI.VBox {
  /**
   * @param {!Emulation.InspectedPagePlaceholder} inspectedPagePlaceholder
   */
  constructor(inspectedPagePlaceholder) {
    super();
    Emulation.DeviceModeView._wrapperInstance = this;
    this._inspectedPagePlaceholder = inspectedPagePlaceholder;
    /** @type {?Emulation.DeviceModeView} */
    this._deviceModeView = null;
    this._toggleDeviceModeAction = UI.actionRegistry.action('emulation.toggle-device-mode');
    const model = self.singleton(Emulation.DeviceModeModel);
    this._showDeviceModeSetting = model.enabledSetting();
    this._showDeviceModeSetting.setRequiresUserAction(!!Runtime.queryParam('hasOtherClients'));
    this._showDeviceModeSetting.addChangeListener(this._update.bind(this, false));
    SDK.targetManager.addModelListener(
        SDK.OverlayModel, SDK.OverlayModel.Events.ScreenshotRequested, this._screenshotRequestedFromOverlay, this);
    this._update(true);
  }

  _toggleDeviceMode() {
    this._showDeviceModeSetting.set(!this._showDeviceModeSetting.get());
  }

  /**
   * @param {boolean=} fullSize
   * @param {!Protocol.Page.Viewport=} clip
   * @return {boolean}
   */
  _captureScreenshot(fullSize, clip) {
    if (!this._deviceModeView)
      this._deviceModeView = new Emulation.DeviceModeView();
    this._deviceModeView.setNonEmulatedAvailableSize(this._inspectedPagePlaceholder.element);
    if (fullSize)
      this._deviceModeView.captureFullSizeScreenshot();
    else if (clip)
      this._deviceModeView.captureAreaScreenshot(clip);
    else
      this._deviceModeView.captureScreenshot();
    return true;
  }

  /**
   * @param {!Common.Event} event
   */
  _screenshotRequestedFromOverlay(event) {
    const clip = /** @type {!Protocol.Page.Viewport} */ (event.data);
    this._captureScreenshot(false, clip);
  }

  /**
   * @param {boolean} force
   */
  _update(force) {
    this._toggleDeviceModeAction.setToggled(this._showDeviceModeSetting.get());
    if (!force) {
      const showing = this._deviceModeView && this._deviceModeView.isShowing();
      if (this._showDeviceModeSetting.get() === showing)
        return;
    }

    if (this._showDeviceModeSetting.get()) {
      if (!this._deviceModeView)
        this._deviceModeView = new Emulation.DeviceModeView();
      this._deviceModeView.show(this.element);
      this._inspectedPagePlaceholder.clearMinimumSize();
      this._inspectedPagePlaceholder.show(this._deviceModeView.element);
    } else {
      if (this._deviceModeView)
        this._deviceModeView.detach();
      this._inspectedPagePlaceholder.restoreMinimumSize();
      this._inspectedPagePlaceholder.show(this.element);
    }
  }
};

/** @type {!Emulation.DeviceModeWrapper} */
Emulation.DeviceModeView._wrapperInstance;

/**
 * @implements {UI.ActionDelegate}
 * @unrestricted
 */
Emulation.DeviceModeWrapper.ActionDelegate = class {
  /**
   * @override
   * @param {!UI.Context} context
   * @param {string} actionId
   * @return {boolean}
   */
  handleAction(context, actionId) {
    if (Emulation.DeviceModeView._wrapperInstance) {
      switch (actionId) {
        case 'emulation.capture-screenshot':
          return Emulation.DeviceModeView._wrapperInstance._captureScreenshot();

        case 'emulation.capture-node-screenshot': {
          const node = UI.context.flavor(SDK.DOMNode);
          if (!node)
            return true;
          async function captureClip() {
            const object = await node.resolveToObject();
            const result = await object.callFunction(function() {
              const rect = this.getBoundingClientRect();
              const docRect = this.ownerDocument.documentElement.getBoundingClientRect();
              return JSON.stringify({
                x: rect.left - docRect.left,
                y: rect.top - docRect.top,
                width: rect.width,
                height: rect.height,
                scale: 1
              });
            });
            const clip = /** @type {!Protocol.Page.Viewport} */ (JSON.parse(result.object.value));
            const response = await node.domModel().target().pageAgent().invoke_getLayoutMetrics({});
            const page_zoom = !response[Protocol.Error] && response.visualViewport.zoom || 1;
            clip.x *= page_zoom;
            clip.y *= page_zoom;
            clip.width *= page_zoom;
            clip.height *= page_zoom;
            Emulation.DeviceModeView._wrapperInstance._captureScreenshot(false, clip);
          }
          captureClip();
          return true;
        }

        case 'emulation.capture-full-height-screenshot':
          return Emulation.DeviceModeView._wrapperInstance._captureScreenshot(true);

        case 'emulation.toggle-device-mode':
          Emulation.DeviceModeView._wrapperInstance._toggleDeviceMode();
          return true;
      }
    }
    return false;
  }
};
<|endoftext|>


<commit_before>/// <binding BeforeBuild='min' Clean='clean' />
"use strict";

var gulp = require("gulp"),
    debug = require("gulp-debug"),
    util = require("gulp-util"),
    rimraf = require("rimraf"),
    merge = require("merge-stream"),
    concat = require("gulp-concat"),
    rename = require("gulp-rename"),
    sass = require("gulp-sass"),
    cssmin = require("gulp-cssmin"),
    uglify = require("gulp-uglify"),
    babel = require("gulp-babel"),
    webpack = require('webpack'),
    sourcemaps = require('gulp-sourcemaps');

var paths = {
    webroot: "./wwwroot/"
};

paths.js = paths.webroot + "js/**/*.js";
paths.jsx = paths.webroot + "js/**/*.jsx";
paths.minJs = paths.webroot + "js/**/*.min.js";

paths.sass = paths.webroot + "sass/**/*.scss";
paths.css = paths.webroot + "css";

paths.concatJsDest = paths.webroot + "js/site.js";
paths.concatJsMinDest = paths.webroot + "js/site.min.js";
paths.concatCssDest = paths.webroot + "css/site.min.css";

gulp.task("clean:js", function (cb) {
    rimraf(paths.concatJsDest, cb);
});

gulp.task("clean:css", function (cb) {
    rimraf(paths.concatCssDest, cb);
});

gulp.task("clean", ["clean:js", "clean:css"]);

gulp.task("compile:jsx", function() {
    return gulp.src([paths.jsx], { base: "." })
        .pipe(debug({ title: 'jsx:' }))
        .pipe(sourcemaps.init())            // start source maps
        .pipe(babel({                       // compile jsx
            presets: ["react", "es2015"]
        }))
        //.pipe(sourcemaps.write())
        .pipe(rename({                      // compiled filename ext
            extname: '.js'
        }))
        .pipe(gulp.dest("."));
});

gulp.task("webpack:build", ["compile:jsx"], function (callback) {
    webpack({
        entry: {
            search: paths.webroot + "js/views/search/main.js"
        },
        output: {
            path: paths.webroot + 'js/dist/',
            filename: '[name].js'
        },
        module: {
            loaders: [
                { test: /\.js$/, loader: 'babel-loader' }
            ]
        }
    }, function(err, stats) {
        util.log('[webpack:build]', stats.toString({
            colors: true
        }));
        callback();
    });
});

gulp.task("min:css", function () {
    return gulp.src([paths.sass])
        .pipe(sourcemaps.init())            // start source maps
        .pipe(sass())                       // compile sass
        .pipe(rename({                      // with new directory, filename ext
            dirname: paths.css,
            extname: '.css'}))
        .pipe(sourcemaps.write())           // create sourcemaps
        .pipe(gulp.dest("."))               // write out compiled files
        .pipe(concat(paths.concatCssDest))  // concat + min
        .pipe(cssmin())
        .pipe(gulp.dest("."));
});

gulp.task("min", ["min:js", "min:css"]);

gulp.task("watch:js", function() {
    gulp.watch([paths.js, paths.jsx], ["webpack:build"]);
});<commit_msg>use standard webpack<commit_after>/// <binding BeforeBuild='min' Clean='clean' />
"use strict";

var gulp = require("gulp"),
    debug = require("gulp-debug"),
    util = require("gulp-util"),
    rimraf = require("rimraf"),
    merge = require("merge-stream"),
    concat = require("gulp-concat"),
    rename = require("gulp-rename"),
    sass = require("gulp-sass"),
    cssmin = require("gulp-cssmin"),
    uglify = require("gulp-uglify"),
    babel = require("gulp-babel"),
    webpack = require('webpack'),
    sourcemaps = require('gulp-sourcemaps');

var paths = {
    webroot: "./wwwroot/"
};

paths.js = paths.webroot + "js/**/*.js";
paths.jsx = paths.webroot + "js/**/*.jsx";
paths.minJs = paths.webroot + "js/**/*.min.js";

paths.sass = paths.webroot + "sass/**/*.scss";
paths.css = paths.webroot + "css";

paths.concatJsDest = paths.webroot + "js/site.js";
paths.concatJsMinDest = paths.webroot + "js/site.min.js";
paths.concatCssDest = paths.webroot + "css/site.min.css";

gulp.task("clean:js", function (cb) {
    rimraf(paths.concatJsDest, cb);
});

gulp.task("clean:css", function (cb) {
    rimraf(paths.concatCssDest, cb);
});

gulp.task("clean", ["clean:js", "clean:css"]);

gulp.task("webpack:build", function (callback) {
    webpack({
        entry: {
            search: paths.webroot + "js/views/search/main.jsx"
        },
        output: {
            path: paths.webroot + 'js/dist/',
            filename: '[name].js'
        },
        module: {
            loaders: [
                {
                    test: /\.jsx?$/,
                    loader: 'babel-loader',
                    query: {
                        presets: ['react', 'es2015']
                    }
                }
            ]
        }
    }, function(err, stats) {
        util.log('[webpack:build]', stats.toString({
            colors: true
        }));
        callback();
    });
});

gulp.task("min:css", function () {
    return gulp.src([paths.sass])
        .pipe(sourcemaps.init())            // start source maps
        .pipe(sass())                       // compile sass
        .pipe(rename({                      // with new directory, filename ext
            dirname: paths.css,
            extname: '.css'}))
        .pipe(sourcemaps.write())           // create sourcemaps
        .pipe(gulp.dest("."))               // write out compiled files
        .pipe(concat(paths.concatCssDest))  // concat + min
        .pipe(cssmin())
        .pipe(gulp.dest("."));
});

gulp.task("min", ["min:js", "min:css"]);

gulp.task("watch:js", function() {
    gulp.watch([paths.js, paths.jsx], ["webpack:build"]);
});<|endoftext|>


<commit_before>/**
 * uncomment.js - Strips comments out of JavaScript code.
 *
 * Copyright (c) 2011 - 2016 Juerg Lehni
 * http://scratchdisk.com/
 *
 * Based on, and expanded from:
 * http://james.padolsey.com/javascript/removing-comments-in-javascript/
 *
 * Distributed under the MIT license.
 */

function uncomment(str, options) {
	options = options || {};
	// Add some padding so we can always look ahead and behind by two chars
	str = ('__' + str + '__').split('');
	var quote = false,
		quoteSign,
		regularExpression = false,
		characterClass = false,
		blockComment = false,
		lineComment = false,
		preserveComment = false;

	for (var i = 0, l = str.length; i < l; i++) {
		// When checking for quote escaping, we also need to check that the
		// escape sign itself is not escaped, as otherwise '\\' would cause
		// the wrong impression of an unclosed string:
		var unescaped = str[i - 1] !== '\\' || str[i - 2] === '\\';

		if (quote) {
			if (str[i] === quoteSign && unescaped)
				quote = false;
		} else if (regularExpression) {
			// Make sure '/'' inside character classes is not considered the end
			// of the regular expression.
			if (str[i] === '[' && unescaped) {
				characterClass = true;
			} else if (str[i] === ']' && unescaped && characterClass) {
				characterClass = false;
			} else if (str[i] === '/' && unescaped && !characterClass) {
				regularExpression = false;
			}
		} else if (blockComment) {
			// Is the block comment closing?
			if (str[i] === '*' && str[i + 1] === '/') {
				if (!preserveComment)
					str[i] = str[i + 1] = '';
				blockComment = preserveComment = false;
				// Increase by 1 to skip closing '/', as it would be mistaken
				// for a regexp otherwise
				i++;
			} else if (!preserveComment) {
				str[i] = '';
			}
		} else if (lineComment) {
			// One-line comments end with the line-break
			if (/[\n\r]/.test(str[i + 1]))
				lineComment = false;
			str[i] = '';
		} else {
			if (/['"]/.test(str[i])) {
				quote = true;
				quoteSign = str[i];
			} else if (str[i] === '/') {
				if (str[i + 1] === '*') {
					// Do not filter out conditional comments /*@ ... */
					// and comments marked as protected /*! ... */
					preserveComment = /[@!]/.test(str[i + 2]);
					if (!preserveComment)
						str[i] = '';
					blockComment = true;
				} else if (str[i + 1] === '/') {
					str[i] = '';
					lineComment = true;
				} else {
					// We need to make sure we don't count normal divisions as
					// regular expresions. Matching this properly is difficult,
					// but if we assume that normal division always have a space
					// after /, a simple check for white space or '='' (for /=)
					// is enough to distinguish divisions from regexps.
					// TODO: Develop a proper check for regexps.
					if (!/[\s=]/.test(str[i + 1])) {
						regularExpression = true;
					}
				}
			}
		}
	}
	// Remove padding again.
	str = str.join('').slice(2, -2);

	if (options.removeEmptyLines || options.mergeEmptyLines) {
		// Strip empty lines that contain only white space and line breaks, as
		// they are left-overs from comment removal.
		str = str.replace(/^([ \t]+(?:\r\n|\n|\r))/gm, function(all) {
			return '';
		});

		// Replace a sequence of two or more line breaks with:
		// - One break, if removeEmptyLines is set.
		// - Two breaks, if mergeEmptyLines is set, meaning they all merge to
		//   one empty line.
		str = str.replace(/(\r\n|\n|\r){2,}/g, function(all, lineBreak) {
			return options.mergeEmptyLines ? lineBreak + lineBreak : lineBreak;
		});
	}

	return str;
}

// Export uncomment function for node
if (typeof module !== 'undefined')
	module.exports = uncomment;
<commit_msg>Improve string processing and filtering performance.<commit_after>/**
 * uncomment.js - Strips comments out of JavaScript code.
 *
 * Copyright (c) 2011 - 2016 Juerg Lehni
 * http://scratchdisk.com/
 *
 * Distributed under the MIT license.
 */

function uncomment(str, options) {
	options = options || {};
	var length = str.length,
		parts = [],
		index = 0,
		quote = false,
		quoteChar,
		regularExpression = false,
		characterClass = false,
		blockComment = false,
		lineComment = false,
		preserveComment = false;

	for (var i = 0; i < length; i++) {
		// When checking for quote escaping, we also need to check that the
		// escape sign itself is not escaped, as otherwise '\\' would cause the
		// wrong impression of an unclosed string:
		var unescaped = str[i - 1] !== '\\' || str[i - 2] === '\\';

		if (quote) {
			if (str[i] === quoteChar && unescaped)
				quote = false;
		} else if (regularExpression) {
			// Make sure '/'' inside character classes is not considered the end
			// of the regular expression.
			if (str[i] === '[' && unescaped) {
				characterClass = true;
			} else if (str[i] === ']' && unescaped && characterClass) {
				characterClass = false;
			} else if (str[i] === '/' && unescaped && !characterClass) {
				regularExpression = false;
			}
		} else if (blockComment) {
			// Is the block comment closing?
			if (str[i] === '*' && str[i + 1] === '/') {
				// Increase by 1 to skip closing '/', as it would be mistaken
				// for a regexp otherwise.
				i++;
				if (!preserveComment) {
					// Next content starts after the comment.
					index = i + 1;
				}
				blockComment = preserveComment = false;
			}
		} else if (lineComment) {
			// One-line comments end with the line-break.
			if (/[\n\r]/.test(str[i + 1])) {
				lineComment = false;
				// Next content starts after the comment.
				index = i + 1;
			}
		} else {
			if (/['"]/.test(str[i])) {
				quote = true;
				// Remember the type of opening quote so we can match it.
				quoteChar = str[i];
			} else if (str[i] === '/') {
				var next = str[i + 1];
				if (next === '*') {
					// Do not filter out conditional comments /*@ ... */
					// and comments marked as protected /*! ... */
					preserveComment = /[@!]/.test(str[i + 2]);
					blockComment = true;
				} else if (next === '/') {
					lineComment = true;
				} else {
					// We need to make sure we don't count normal divisions as
					// regular expressions. Matching this properly is difficult,
					// but if we assume that normal division always have a space
					// after /, a simple check for white space or '='' (for /=)
					// is enough to distinguish divisions from regexps.
					// TODO: Develop a proper check for regexps.
					regularExpression = !/[\s=]/.test(next);
				}
				if (index < i && (lineComment ||
						blockComment && !preserveComment)) {
					// Insert valid content up to the comment.
					parts.push(str.substring(index, index = i));
				}
			}
		}
	}
	if (index < length && !lineComment && (!blockComment || preserveComment)) {
		// Insert valid content up to the end of the string.
		parts.push(str.substring(index, length));
	}
	// Convert back to one string, by concatenating the valid parts.
	str = parts.join('');

	if (options.removeEmptyLines || options.mergeEmptyLines) {
		// Strip empty lines that contain only white space and line breaks, as
		// they are left-overs from comment removal.
		str = str.replace(/^([ \t]+(?:\r\n|\n|\r))/gm, function(all) {
			return '';
		});

		// Replace a sequence of two or more line breaks with:
		// - One break, if removeEmptyLines is set.
		// - Two breaks, if mergeEmptyLines is set, meaning they all merge to
		//   one empty line.
		str = str.replace(/(\r\n|\n|\r){2,}/g, function(all, lineBreak) {
			return options.mergeEmptyLines ? lineBreak + lineBreak : lineBreak;
		});
	}

	return str;
}

// Export uncomment function for node
if (typeof module !== 'undefined')
	module.exports = uncomment;
<|endoftext|>


<commit_before>(function (Q, $) {
/**
 * @module Q-tools
 */

/**
 * Implements lazy-loading for various types of elements.
 * By default, has implementations for "img" and "Q_tool" selectors.
 * The "Q_tool" handler only works with tools whose elements have a "data-q-lazyload" attribute .
 * Note that the elements must have a stable, nonzero width height set in the CSS even
 * if they are empty, otherwise they might not be lazy-loaded, and they might
 * thrash back and forth if removed.
 * @class Q lazyload
 * @constructor
 * @param {Object} [options] Override various options for this tool
 * @param {Array} [options.handle] Set this to
 * @param {Object} [options.handlers] You can modify the defaults by passing an object
 *    that looks like {handlerName: { selector: String, entering: Function, exiting: Function, preparing: Function}}
 *    Function "entering" receives (element, intersectionObserverEntry)
 *    Function "exiting" receives (element, intersectionObserverEntry)
 *    Function "preparing" receives (element) and is used the first time to prepare the element
 *    Both functions must return true if the element was modified.
 * @param {Object} [observerOptions] Override any options to pass to IntersectionObserver
 * @return {Q.Tool}
 */
Q.Tool.define('Q/lazyload', function (options) {

	var tool = this;
	var state = this.state;

	var Elp = Element.prototype;

	Q.ensure(window.IntersectionObserver, _polyfill, function () {
		// Observe whatever is on the page already
		tool.observer = _createObserver(tool, tool.element);
		tool.observe(tool.prepare(tool.element, false));

		// Override innerHTML

		var originalSet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').set;
		var originalGet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').get;

		Object.defineProperty(Elp, 'innerHTML', {
			set: function (html) {
				var element = document.createElement('div');
				originalSet.call(element, html);
				var found = false;
				Q.each(state.handlers, function (name, info) {
					var elements = element.querySelectorAll
						? Array.from(element.querySelectorAll(info.selector))
						: [];
					if (elements.length) {
						found = true;
						return false;
					}
				});
				if (found) {
					html = originalGet.call(element);
				}
				originalSet.call(this, html);
				if (found) {
					tool.observe(tool.prepare(this, true));
				}
				return html;
			},
			get: originalGet
		});

		Q.each(['insertBefore', 'appendChild'], function (i, fn) {
			var orig = Elp[fn];
			Elp[fn] = function (element) {
				if (!element) {
					return;
				}
				tool.observe(tool.prepare(element, true));
				return orig.apply(this, arguments);
			};
		});
	});

},

{
	root: null,
	handlers: {
		img: {
			selector: 'img',
			entering: function (img, entry) {
				function _loaded() {
					img.addClass('Q_lazy_loaded');
				}
				var src = img.getAttribute('data-lazyload-src');
				if (src) {
					img.setAttribute('src', Q.url(src));
					img.removeAttribute('data-lazyload-src');
					img.addClass('Q_lazy_load');
					if (img.complete) {
						_loaded();
					}
					img.addEventListener('load', _loaded);
				}
				return true;
			},
			exiting: function (img) {
				// no need to do anything
				return true;
			},
			preparing: function (img, beingInsertedIntoDOM) {
				if (!beingInsertedIntoDOM) {
					return true; // too late anyway, browser will load image
				}
				if (img.hasClass('Q_lazy_loaded')) {
					returrn true; // this was already lazy-loaded before
				}
				var src = img.getAttribute('src');
				if (src && src.substr(0, 5) !== 'data:'
				&& !img.hasAttribute('data-lazyload-src')) {
					img.setAttribute('data-lazyload-src', Q.url(src));
					img.setAttribute('src', Q.url(
						Q.getObject('Q.images.lazyload.loadingSrc')
						|| "{{Q}}/img/throbbers/transparent.gif"
					));
				}
				return true;
			}
		},
		tool: {
			selector: '.Q_tool',
			entering: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& (!element.Q || !element.Q.tool)) {
					element.addClass('Q_lazy_load');
					element.setAttribute('data-q-lazyload', 'activating');
					Q.activate(element, function () {
						element.setAttribute('data-q-lazyload', 'activated');
						element.addClass('Q_lazy_loaded');
					}, {}, true);
					return true;
				}
			},
			exiting: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& element.Q.tool) {
					Q.Tool.remove(element);
					element.removeClass('Q_lazy_loading');
					element.removeClass('Q_lazy_loaded');
					element.setAttribute('data-q-lazyload', 'removed');
					if (this.state.handlers.tool.exitingRemoveHTML) {
						element.innerHTML = '';
					}
				}
				return true;
			},
			preparing: function (element) {
				return true;
			},
			exitingRemoveHTML: true
		}
	},
	observerOptions: {
		root: null,
		rootMargin: '0px',
		threshold: 0
	}
},

{
	prepare: function (container, beingInsertedIntoDOM) {
		var tool = this;
		var found = [];
		Q.each(tool.state.handlers, function (name, info) {
			var elements = container.querySelectorAll
				? Array.from(container.querySelectorAll(info.selector))
				: [];
			if (container.matches && container.matches(info.selector)) {
				elements.push(container);
			}
			Q.each(elements, function (i, element) {
				if (info.preparing.call(tool, element, beingInsertedIntoDOM) === true) {
					found.push(element);
				}
			});
		});
		return found;
	},
	observe: function (elements) {
		var tool = this;
		Q.each(elements, function (i, element) {
			tool.observer.observe(element);
		});
	}
});

function _createObserver(tool, container) {
	return new IntersectionObserver(function (entries, observer) {
		Q.each(entries, function (i, entry) {
			Q.each(tool.state.handlers, function (name, info) {
				if (entry.target.matches && entry.target.matches(info.selector)) {
					if (entry.isIntersecting) {
						info.entering.call(tool, entry.target, entry);
					} else  {
						var rect = entry.target.getBoundingClientRect();
						if (rect.width > 0 && rect.height > 0) {
							// also covers !document.body.contains(entry.target)
							info.exiting.call(tool, entry.target, entry);
						} // otherwise it might get a false positive
					}
				}
			});
		});
	}, tool.state.observerOptions);
}

function _polyfill(callback) {
	// Exit early if all IntersectionObserver and IntersectionObserverEntry
	// features are natively supported.
	if ('IntersectionObserver' in window &&
	    'IntersectionObserverEntry' in window &&
	    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {

	  // Minimal polyfill for Edge 15's lack of `isIntersecting`
	  // See: https://github.com/w3c/IntersectionObserver/issues/211
	  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
	    Object.defineProperty(window.IntersectionObserverEntry.prototype,
	      'isIntersecting', {
	      get: function () {
	        return this.intersectionRatio > 0;
	      }
	    });
	  }
	  return Q.handle(callback);
	}
	Q.addScript('{{Q}}/js/polyfills/IntersectionObserver.js', callback);
}

_polyfill();

})(Q, jQuery);<commit_msg>Fixed a typo<commit_after>(function (Q, $) {
/**
 * @module Q-tools
 */

/**
 * Implements lazy-loading for various types of elements.
 * By default, has implementations for "img" and "Q_tool" selectors.
 * The "Q_tool" handler only works with tools whose elements have a "data-q-lazyload" attribute .
 * Note that the elements must have a stable, nonzero width height set in the CSS even
 * if they are empty, otherwise they might not be lazy-loaded, and they might
 * thrash back and forth if removed.
 * @class Q lazyload
 * @constructor
 * @param {Object} [options] Override various options for this tool
 * @param {Array} [options.handle] Set this to
 * @param {Object} [options.handlers] You can modify the defaults by passing an object
 *    that looks like {handlerName: { selector: String, entering: Function, exiting: Function, preparing: Function}}
 *    Function "entering" receives (element, intersectionObserverEntry)
 *    Function "exiting" receives (element, intersectionObserverEntry)
 *    Function "preparing" receives (element) and is used the first time to prepare the element
 *    Both functions must return true if the element was modified.
 * @param {Object} [observerOptions] Override any options to pass to IntersectionObserver
 * @return {Q.Tool}
 */
Q.Tool.define('Q/lazyload', function (options) {

	var tool = this;
	var state = this.state;

	var Elp = Element.prototype;

	Q.ensure(window.IntersectionObserver, _polyfill, function () {
		// Observe whatever is on the page already
		tool.observer = _createObserver(tool, tool.element);
		tool.observe(tool.prepare(tool.element, false));

		// Override innerHTML

		var originalSet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').set;
		var originalGet = Object.getOwnPropertyDescriptor(Elp, 'innerHTML').get;

		Object.defineProperty(Elp, 'innerHTML', {
			set: function (html) {
				var element = document.createElement('div');
				originalSet.call(element, html);
				var found = false;
				Q.each(state.handlers, function (name, info) {
					var elements = element.querySelectorAll
						? Array.from(element.querySelectorAll(info.selector))
						: [];
					if (elements.length) {
						found = true;
						return false;
					}
				});
				if (found) {
					html = originalGet.call(element);
				}
				originalSet.call(this, html);
				if (found) {
					tool.observe(tool.prepare(this, true));
				}
				return html;
			},
			get: originalGet
		});

		Q.each(['insertBefore', 'appendChild'], function (i, fn) {
			var orig = Elp[fn];
			Elp[fn] = function (element) {
				if (!element) {
					return;
				}
				tool.observe(tool.prepare(element, true));
				return orig.apply(this, arguments);
			};
		});
	});

},

{
	root: null,
	handlers: {
		img: {
			selector: 'img',
			entering: function (img, entry) {
				function _loaded() {
					img.addClass('Q_lazy_loaded');
				}
				var src = img.getAttribute('data-lazyload-src');
				if (src) {
					img.setAttribute('src', Q.url(src));
					img.removeAttribute('data-lazyload-src');
					img.addClass('Q_lazy_load');
					if (img.complete) {
						_loaded();
					}
					img.addEventListener('load', _loaded);
				}
				return true;
			},
			exiting: function (img) {
				// no need to do anything
				return true;
			},
			preparing: function (img, beingInsertedIntoDOM) {
				if (!beingInsertedIntoDOM) {
					return true; // too late anyway, browser will load image
				}
				if (img.hasClass('Q_lazy_loaded')) {
					return true; // this was already lazy-loaded before
				}
				var src = img.getAttribute('src');
				if (src && src.substr(0, 5) !== 'data:'
				&& !img.hasAttribute('data-lazyload-src')) {
					img.setAttribute('data-lazyload-src', Q.url(src));
					img.setAttribute('src', Q.url(
						Q.getObject('Q.images.lazyload.loadingSrc')
						|| "{{Q}}/img/throbbers/transparent.gif"
					));
				}
				return true;
			}
		},
		tool: {
			selector: '.Q_tool',
			entering: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& (!element.Q || !element.Q.tool)) {
					element.addClass('Q_lazy_load');
					element.setAttribute('data-q-lazyload', 'activating');
					Q.activate(element, function () {
						element.setAttribute('data-q-lazyload', 'activated');
						element.addClass('Q_lazy_loaded');
					}, {}, true);
					return true;
				}
			},
			exiting: function (element, entry) {
				if (element.hasAttribute('data-q-lazyload')
				&& element.Q.tool) {
					Q.Tool.remove(element);
					element.removeClass('Q_lazy_loading');
					element.removeClass('Q_lazy_loaded');
					element.setAttribute('data-q-lazyload', 'removed');
					if (this.state.handlers.tool.exitingRemoveHTML) {
						element.innerHTML = '';
					}
				}
				return true;
			},
			preparing: function (element) {
				return true;
			},
			exitingRemoveHTML: true
		}
	},
	observerOptions: {
		root: null,
		rootMargin: '0px',
		threshold: 0
	}
},

{
	prepare: function (container, beingInsertedIntoDOM) {
		var tool = this;
		var found = [];
		Q.each(tool.state.handlers, function (name, info) {
			var elements = container.querySelectorAll
				? Array.from(container.querySelectorAll(info.selector))
				: [];
			if (container.matches && container.matches(info.selector)) {
				elements.push(container);
			}
			Q.each(elements, function (i, element) {
				if (info.preparing.call(tool, element, beingInsertedIntoDOM) === true) {
					found.push(element);
				}
			});
		});
		return found;
	},
	observe: function (elements) {
		var tool = this;
		Q.each(elements, function (i, element) {
			tool.observer.observe(element);
		});
	}
});

function _createObserver(tool, container) {
	return new IntersectionObserver(function (entries, observer) {
		Q.each(entries, function (i, entry) {
			Q.each(tool.state.handlers, function (name, info) {
				if (entry.target.matches && entry.target.matches(info.selector)) {
					if (entry.isIntersecting) {
						info.entering.call(tool, entry.target, entry);
					} else  {
						var rect = entry.target.getBoundingClientRect();
						if (rect.width > 0 && rect.height > 0) {
							// also covers !document.body.contains(entry.target)
							info.exiting.call(tool, entry.target, entry);
						} // otherwise it might get a false positive
					}
				}
			});
		});
	}, tool.state.observerOptions);
}

function _polyfill(callback) {
	// Exit early if all IntersectionObserver and IntersectionObserverEntry
	// features are natively supported.
	if ('IntersectionObserver' in window &&
	    'IntersectionObserverEntry' in window &&
	    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {

	  // Minimal polyfill for Edge 15's lack of `isIntersecting`
	  // See: https://github.com/w3c/IntersectionObserver/issues/211
	  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
	    Object.defineProperty(window.IntersectionObserverEntry.prototype,
	      'isIntersecting', {
	      get: function () {
	        return this.intersectionRatio > 0;
	      }
	    });
	  }
	  return Q.handle(callback);
	}
	Q.addScript('{{Q}}/js/polyfills/IntersectionObserver.js', callback);
}

_polyfill();

})(Q, jQuery);<|endoftext|>


<commit_before>(function() {
  slMapClickHandler = function(infobox) {
    // Private attributes

    var map_click_handler = this;

    var circle = null;

    // Public attributes and functions

    /**
     * @expose
     * Click handler which shows a info box at the click location.
     */
    map_click_handler.trigger = function(e) {
      if (circle !== null)
        hideCircle(0);

      // create bounding box in map coordinates around mouse cursor
      var pixel = new OpenLayers.Pixel(e.layerX, e.layerY);
      var clickTolerance = 15;
      var llPx = pixel.add(-clickTolerance / 2, clickTolerance / 2);
      var urPx = pixel.add(clickTolerance / 2, -clickTolerance / 2);
      var ll = map.getLonLatFromPixel(llPx);
      var ur = map.getLonLatFromPixel(urPx);
      var loc = map.getLonLatFromPixel(pixel);

      // search for a aircraft position within the bounding box
      var nearest = searchForPlane(
          new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat),
          loc,
          clickTolerance);

      if (nearest === null) return;

      var index = nearest.from;
      var flight = flights[nearest.fid];
      var dx = nearest.along;

      var lon = flight.lonlat[index].lon +
          (flight.lonlat[index + 1].lon - flight.lonlat[index].lon) * dx;
      var lat = flight.lonlat[index].lat +
          (flight.lonlat[index + 1].lat - flight.lonlat[index].lat) * dx;
      var time = flight.t[index] +
          (flight.t[index + 1] - flight.t[index]) * dx;

      infobox.empty();
      infobox.latlon = map.getLonLatFromPixel(pixel);

      // flight info

      var flight_info = $(
          '' +
          (flight.additional && flight.additional['registration'] || '') +
          ''
          );

      infobox.append(flight_info);

      // near flights link

      var get_near_flights = $(
          '
' +
          'Load nearby flights' +
          '
'
          );

      get_near_flights.on('click touchend', function(e) {
        infobox.hide();
        getNearFlights(lon, lat, time, flight);
      });

      infobox.append(get_near_flights);

      // general events

      map.events.register('move', this, function(e) {
        if (e.object.getExtent().containsLonLat(infobox.latlon)) {
          var pixel = e.object.getPixelFromLonLat(infobox.latlon);
          infobox.css('left', (pixel.x + 5) + 'px');
          infobox.css('top', (pixel.y - infobox.height() / 2) + 'px');
        } else {
          infobox.hide();
          hideCircle(0);
        }
      });

      // hide box when clicked outside
      // use OL click event which doesn't get fired on panning
      map.events.register('click', this, function(e) {
        if (get_near_flights.find(e.target).length === 0 &&
            flight_info.find(e.target).length === 0) {
          infobox.hide();
          hideCircle(0);
        }
      });

      infobox.css('left', (pixel.x + 5) + 'px');
      infobox.css('top', (pixel.y - infobox.height() / 2) + 'px');

      infobox.show();
      showCircle(lon, lat);

      return false; // stop bubbeling
    };

    // Private functions

    /**
     * Show a circle at the clicked position
     *
     * @param {Number} lon Longitude.
     * @param {Number} lat Latitude.
     */
    function showCircle(lon, lat) {
      // first, calculate how many map units are 1000 meters. This is
      // approximate, but close enough for our purpose. In google maps
      // (and openstreetmap) spherical projection (aka EPSG:900913 or
      // EPSG:3857), one meter at the equator is exactly one unit.
      // Cut off at 85 deg.
      var distance_deg = 1000 / Math.cos(Math.PI / 180 *
          Math.min(Math.abs(lat, 85)));

      var point = new OpenLayers.Geometry.Point(lon, lat)
                  .transform(WGS84_PROJ, map.getProjectionObject());

      circle = new OpenLayers.Feature.Vector(
          new OpenLayers.Geometry.Polygon.createRegularPolygon(point,
              distance_deg, 40, 0));

      // draw this circle and fade the inner fill within 500ms
      circle.renderIntent = 'nearestCircle';

      map.getLayersByName('Flight')[0].addFeatures(circle);

      // escape points in the id, see
      // http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_select_an_
      // element_by_an_ID_that_has_characters_used_in_CSS_notation.3F
      var circle_id = '#' + circle.geometry.id.replace(/(:|\.)/g, '\\$1');
      $(circle_id).animate({fillOpacity: 0}, 500);
    };

    /**
     * Hides the search circle
     *
     * @param {Integer} duration Fade duration.
     */
    function hideCircle(duration) {
      if (circle === null) return;

      var circle_id = '#' + circle.geometry.id.replace(/(:|\.)/g, '\\$1');
      // fade circle out and remove it from layer
      $(circle_id).animate({opacity: 0}, duration, function() {
        // check if circle still exists, because it might got deleted before
        // the animation was done.
        if (circle !== null) {
          map.getLayersByName('Flight')[0].destroyFeatures(circle);
          circle = null;
        }
      });
    };

    /**
     * Request near flights via ajax
     *
     * @param {Number} lon Longitude.
     * @param {Number} lat Latitude.
     * @param {Number} time Time.
     * @param {Object} flight Flight.
     */
    function getNearFlights(lon, lat, time, flight) {
      $.ajax('/flights/' + flight.sfid + '/near?lon=' + lon +
          '&lat=' + lat + '&time=' + time, {
            success: function(data) {
              for (var i = 0; i < data.flights.length; ++i) {
                // skip retrieved flight if already on map
                var next = false;
                for (var fid = 0; fid < flights.length; ++fid)
                  if (flights[fid].sfid == data.flights[i].sfid) next = true;
                  if (next) continue;

                  var flight_id = addFlight(data.flights[i].sfid,
                      data.flights[i].encoded.points,
                      data.flights[i].encoded.levels,
                      data.flights[i].num_levels,
                      data.flights[i].barogram_t,
                      data.flights[i].barogram_h,
                      data.flights[i].enl,
                      data.flights[i].zoom_levels,
                      data.flights[i].contests,
                      data.flights[i].additional);
              }
            },
            complete: function() {
              hideCircle(1000);
            }
          });
    }
  };
})();
<commit_msg>map-click-handler.js: use plane location as anchor<commit_after>(function() {
  slMapClickHandler = function(infobox) {
    // Private attributes

    var map_click_handler = this;

    var circle = null;

    // Public attributes and functions

    /**
     * @expose
     * Click handler which shows a info box at the click location.
     */
    map_click_handler.trigger = function(e) {
      if (circle !== null)
        hideCircle(0);

      // create bounding box in map coordinates around mouse cursor
      var pixel = new OpenLayers.Pixel(e.layerX, e.layerY);
      var clickTolerance = 15;
      var llPx = pixel.add(-clickTolerance / 2, clickTolerance / 2);
      var urPx = pixel.add(clickTolerance / 2, -clickTolerance / 2);
      var ll = map.getLonLatFromPixel(llPx);
      var ur = map.getLonLatFromPixel(urPx);
      var loc = map.getLonLatFromPixel(pixel);

      var loc_wgs84 = loc.clone()
          .transform(map.getProjectionObject(), WGS84_PROJ);
      var lon = loc_wgs84.lon,
          lat = loc_wgs84.lat;

      // search for a aircraft position within the bounding box
      var nearest = searchForPlane(
          new OpenLayers.Bounds(ll.lon, ll.lat, ur.lon, ur.lat),
          loc,
          clickTolerance);

      if (nearest === null) return;

      var index = nearest.from;
      var flight = flights[nearest.fid];
      var dx = nearest.along;

      lon = flight.lonlat[index].lon +
          (flight.lonlat[index + 1].lon - flight.lonlat[index].lon) * dx;
      lat = flight.lonlat[index].lat +
          (flight.lonlat[index + 1].lat - flight.lonlat[index].lat) * dx;
      var time = flight.t[index] +
          (flight.t[index + 1] - flight.t[index]) * dx;

      infobox.empty();

      // flight info

      var flight_info = $(
          '' +
          (flight.additional && flight.additional['registration'] || '') +
          ''
          );

      infobox.append(flight_info);

      // near flights link

      var get_near_flights = $(
          '
' +
          'Load nearby flights' +
          '
'
          );

      get_near_flights.on('click touchend', function(e) {
        infobox.hide();
        getNearFlights(lon, lat, time, flight);
      });

      infobox.append(get_near_flights);

      // general events

      map.events.register('move', this, function(e) {
        if (e.object.getExtent().containsLonLat(infobox.latlon)) {
          var pixel = e.object.getPixelFromLonLat(infobox.latlon);
          infobox.css('left', (pixel.x + 5) + 'px');
          infobox.css('top', (pixel.y - infobox.height() / 2) + 'px');
        } else {
          infobox.hide();
          hideCircle(0);
        }
      });

      // hide box when clicked outside
      // use OL click event which doesn't get fired on panning
      map.events.register('click', this, function(e) {
        if (get_near_flights.find(e.target).length === 0 &&
            flight_info.find(e.target).length === 0) {
          infobox.hide();
          hideCircle(0);
        }
      });

      infobox.latlon = new OpenLayers.LonLat(lon, lat)
          .transform(WGS84_PROJ, map.getProjectionObject());

      pixel = e.object.getPixelFromLonLat(infobox.latlon);
      infobox.css('left', (pixel.x + 5) + 'px');
      infobox.css('top', (pixel.y - infobox.height() / 2) + 'px');

      infobox.show();
      showCircle(lon, lat);

      return false; // stop bubbeling
    };

    // Private functions

    /**
     * Show a circle at the clicked position
     *
     * @param {Number} lon Longitude.
     * @param {Number} lat Latitude.
     */
    function showCircle(lon, lat) {
      // first, calculate how many map units are 1000 meters. This is
      // approximate, but close enough for our purpose. In google maps
      // (and openstreetmap) spherical projection (aka EPSG:900913 or
      // EPSG:3857), one meter at the equator is exactly one unit.
      // Cut off at 85 deg.
      var distance_deg = 1000 / Math.cos(Math.PI / 180 *
          Math.min(Math.abs(lat, 85)));

      var point = new OpenLayers.Geometry.Point(lon, lat)
                  .transform(WGS84_PROJ, map.getProjectionObject());

      circle = new OpenLayers.Feature.Vector(
          new OpenLayers.Geometry.Polygon.createRegularPolygon(point,
              distance_deg, 40, 0));

      // draw this circle and fade the inner fill within 500ms
      circle.renderIntent = 'nearestCircle';

      map.getLayersByName('Flight')[0].addFeatures(circle);

      // escape points in the id, see
      // http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_select_an_
      // element_by_an_ID_that_has_characters_used_in_CSS_notation.3F
      var circle_id = '#' + circle.geometry.id.replace(/(:|\.)/g, '\\$1');
      $(circle_id).animate({fillOpacity: 0}, 500);
    };

    /**
     * Hides the search circle
     *
     * @param {Integer} duration Fade duration.
     */
    function hideCircle(duration) {
      if (circle === null) return;

      var circle_id = '#' + circle.geometry.id.replace(/(:|\.)/g, '\\$1');
      // fade circle out and remove it from layer
      $(circle_id).animate({opacity: 0}, duration, function() {
        // check if circle still exists, because it might got deleted before
        // the animation was done.
        if (circle !== null) {
          map.getLayersByName('Flight')[0].destroyFeatures(circle);
          circle = null;
        }
      });
    };

    /**
     * Request near flights via ajax
     *
     * @param {Number} lon Longitude.
     * @param {Number} lat Latitude.
     * @param {Number} time Time.
     * @param {Object} flight Flight.
     */
    function getNearFlights(lon, lat, time, flight) {
      $.ajax('/flights/' + flight.sfid + '/near?lon=' + lon +
          '&lat=' + lat + '&time=' + time, {
            success: function(data) {
              for (var i = 0; i < data.flights.length; ++i) {
                // skip retrieved flight if already on map
                var next = false;
                for (var fid = 0; fid < flights.length; ++fid)
                  if (flights[fid].sfid == data.flights[i].sfid) next = true;
                  if (next) continue;

                  var flight_id = addFlight(data.flights[i].sfid,
                      data.flights[i].encoded.points,
                      data.flights[i].encoded.levels,
                      data.flights[i].num_levels,
                      data.flights[i].barogram_t,
                      data.flights[i].barogram_h,
                      data.flights[i].enl,
                      data.flights[i].zoom_levels,
                      data.flights[i].contests,
                      data.flights[i].additional);
              }
            },
            complete: function() {
              hideCircle(1000);
            }
          });
    }
  };
})();
<|endoftext|>


<commit_before>/*
  A wrapper for native DOM events when using event delegation via
  `DOMElement.on(eventName, selector, handler)`.

  @param [Component] owner
  @param [Element] selectedTarget native DOM element
  @param [Event] originalEvent native DOM event
*/
class DelegatedEvent {
  constructor(owner, selectedTarget, originalEvent) {
    this.owner = owner
    this.target = selectedTarget
    this.originalEvent = originalEvent
  }
}

DelegatedEvent.delegatedHandler = function(listener, top) {
  let handler = listener.handler
  let context = listener.context
  let selector = listener.options.selector
  return function(event) {
    let el = event.target
    while(el) {
      if (matches(el, selector)) {
        handler(new DelegatedEvent(context, event.target, event))
        break
      }
      if (el === top) {
        break
      }
      el = el.parentNode;
    }
  }
}

export default DelegatedEvent
<commit_msg>Fix regression.<commit_after>import DefaultDOMElement from './DOMElement'

/*
  A wrapper for native DOM events when using event delegation via
  `DOMElement.on(eventName, selector, handler)`.

  @param [Component] owner
  @param [Element] selectedTarget native DOM element
  @param [Event] originalEvent native DOM event
*/
class DelegatedEvent {
  constructor(owner, selectedTarget, originalEvent) {
    this.owner = owner
    this.target = selectedTarget
    this.originalEvent = originalEvent
  }
}

DelegatedEvent.delegatedHandler = function(listener, top) {
  let handler = listener.handler
  let context = listener.context
  let selector = listener.options.selector
  return function(event) {
    let el = DefaultDOMElement.wrap(event.target)
    while(el) {
      if (el.is(selector)) {
        handler(new DelegatedEvent(context, event.target, event))
        break
      }
      if (el === top) {
        break
      }
      el = el.parentNode;
    }
  }
}

export default DelegatedEvent
<|endoftext|>


<commit_before>// Custom test suite (without webpack) by Jason Steck
(function(){
  const PASS = 1;
  const FAIL = 0;
  const NO_EXPECTATIONS = -1;

  let topContext = {
    descriptionChain: [],
    beforeEachChain: [],
    afterEachChain: [],
    its: [],
    describes: [],
    contexts: [],
  };
  /*  during setup  */
  let currentContext = topContext;

  window.describe = (str, func) => {
    currentContext.describes.push([str, func]);
  };

  window.beforeEach = (func) => {
    currentContext.beforeEachChain.push(func);
  };

  window.it = (str, func) => {
    if(typeof func !== 'function') throw new Error(`Missing function in 'it' block of "${str}"`);
    currentContext.its.push([str, func]);
  };

  window.afterEach = (func) => {
    currentContext.afterEachChain.unshift(func);
  };

  /*  during tests  */
  let debugMode = false;
  let spies = [];

  function ResultsClass() {
    this.all = [];
    this.failed = [];
    this.noExpectations = [];
  }
  ResultsClass.prototype.addResult = function (testResult){
    this.all.push(testResult);
    if(testResult.result === FAIL) {
      this.failed.push(testResult);
    } else if(testResult.result === NO_EXPECTATIONS) {
      this.noExpectations.push(testResult);
    }
  };

  function TestResultClass(test) {
    this.testPath = null;
    this.test = test;
    this.result = NO_EXPECTATIONS;
    this.failReasons = [];

    this.testPath = currentContext.descriptionChain.slice(0);
    this.testPath.push(test[0]);
  }
  TestResultClass.prototype.failExpectation = function(reason, stack){
    this.result = FAIL;
    this.failReasons.push(reason+'\n'+stack);
  };
  TestResultClass.prototype.passExpectation = function() {
    if(this.result === NO_EXPECTATIONS) {
      this.result = PASS;
    }
  };

  let results = null;
  let currentTestResult = null;

  function getErrorStack() {
    return (new Error()).stack.split('\n').slice(5,6).join('\n');
  }

  function failWithConsole(msg) {
    currentTestResult.failExpectation(msg, getErrorStack());
    if(debugMode){
      consoleFailMessage(failMessage(currentTestResult));
      return true;
    }
    return false;
  }

  function isEqual(a,b) {
    if(typeof a !== typeof b) return false;
    if(a === Object(a)){
      return objectsEqual(a,b);
    } else if(Array.isArray(a)) {
      return arraysEqual(a,b)
    } else {
      return a == b;
    }
  }

  function objectsEqual(a, b) {
    let aProps = Object.getOwnPropertyNames(a);
    let bProps = Object.getOwnPropertyNames(b);

    if (aProps.length !== bProps.length) return false;

    for (let i = 0; i < aProps.length; i++) {
      let propName = aProps[i];

      if (!isEqual(a[propName], b[propName])) {
        return false;
      }
    }
    return true;
  }

  function arraysEqual(a, b) {
    if (a === b) return true;
    if (a.length !== b.length) return false;

    for (let i = 0; i < a.length; i++) {
      if (a[i] !== b[i]) return false;
    }
    return true;
  }

  function getOutputFormat(exp) {
    if(typeof exp === 'function') {
      return exp.toString();
    }
    return JSON.stringify(exp);
  }

  function toEqual(actual, expected, not) {
    if(isEqual(actual,expected) ^ not){
      currentTestResult.passExpectation();
    } else {
      let a = getOutputFormat(actual);
      let b = getOutputFormat(expected);
      currentTestResult.failExpectation(`Expected ${a} \nto equal ${b}`, getErrorStack());
      if (debugMode) {
        consoleFailMessage(failMessage(currentTestResult));
        debugger;
      }
    }
  }

  function toBe(actual, expected, not) {
    if((actual === expected) ^ not){
      currentTestResult.passExpectation();
    } else {
      let a = getOutputFormat(actual);
      let b = getOutputFormat(expected);
      currentTestResult.failExpectation(`Expected ${a} \n   to be ${b}`, getErrorStack());
      if(debugMode){
        consoleFailMessage(failMessage(currentTestResult));
        debugger;
      }
    }
  }

  function toThrow(actual, exception, not) {
    let threw = false;
    let correctlyThrew = false;
    let error = null;
    try {
      actual();
    } catch (err) {
      error = err;
      if(err == exception ||
        (err.name !== undefined &&
        err.message!== undefined &&
        err.name === exception.name &&
        isEqual(err.message, exception.message))) {

        correctlyThrew = true;
      }
      threw = true;
    }
    if(not) {
      if(correctlyThrew) {
        if(failWithConsole(`Expected ${actual} \nnot to throw "${exception}"\n but it did`)) debugger;
      } else {
        currentTestResult.passExpectation();
      }
    } else {
      if(correctlyThrew) {
        currentTestResult.passExpectation();
      } else if(threw) {
        let notString = not?'not':'';
        if(failWithConsole(`Expected ${actual} \n${notString}to throw "${exception}"\n but got "${error}"`)) debugger;
      } else {
        if(failWithConsole(`Expected ${actual} \nto throw "${exception}" but didn't get anything`)) debugger;
      }
    }
  }

  window.expect = (actual) => {
    return {
      not: {
        toThrow: expected => {
          toThrow(actual, expected, true);
        },
        toEqual: expected => {
          toEqual(actual, expected, true);
        },
        toBe: expected => {
          toBe(actual, expected, true);
        },
      },
      toThrow: exception => {
        toThrow(actual, exception, false);
      },
      toEqual: expected => {
        toEqual(actual, expected, false);
      },
      toBe: expected => {
        toBe(actual, expected, false);
      },
    }
  };

  function ensureSpy(str, obj) {
    if(!(obj && obj[str] && obj[str]._isSpy)) {
      return obj[str] = newSpyGuy(str, obj);
    }
    return obj[str];
  }

  function newSpyGuy(str, obj) {
    function spyGuy(...args){
      let returnValue = undefined;
      if(self.callFake) {
        returnValue = self.callFake.apply(this, args);
      }
      if(self.returnValue) {
        returnValue = self.returnValue;
      }
      return returnValue;
    }
    let self = spyGuy;
    spyGuy._isSpy = true;
    spyGuy.methodName = str;
    spyGuy.object = obj;
    spyGuy.originalFunc = obj && obj[str];
    spyGuy.callFake = null;
    spyGuy.returnValue = null;

    spies.push(spyGuy);
    return spyGuy;
  }

  window.stub = function(obj) {
    return new Proxy({}, {
      get: function(_, str) {
        let spyGuy = ensureSpy(str, obj);
        function spyHandler(){}
        spyHandler.toReturn = val => {
          spyGuy.returnValue = val;
          return spyHandler;
        };
        return spyHandler;
      },
      set: function(_, str, val){
        ensureSpy(str, obj);
        if(typeof val === 'function') {
          obj[str].callFake = val;
        }
      },
    });
  };

  function indentLines(lines, pad = '  '){
    let padding = '';
    return lines.map(desc => {
      return [padding+desc, padding+=pad][0];
    })
  }

  function failMessage(testResult) {
    let descriptions = indentLines(testResult.testPath).join('\n');
    return `${descriptions} \n${testResult.failReasons.join('\n')}`;
  }

  function consoleFailMessage(msg) {
    console.log('%c Failure:', 'color: red; font-weight: bold;');
    console.log(msg);
  }

  /*  spec execution  */
  function parseContext(context) {
    let prevContext = currentContext;
    context.describes.forEach(desc => {
      let newContext = {
        descriptionChain: context.descriptionChain.slice(0),
        beforeEachChain: context.beforeEachChain.slice(0),
        afterEachChain: context.afterEachChain.slice(0),
        its: [],
        describes: [],
        contexts: [],
      };
      newContext.descriptionChain.push(desc[0]);
      context.contexts.push(newContext);
      currentContext = newContext;
      desc[1]();
      parseContext(newContext);
    });
    currentContext = prevContext;
  }

  function runContext(context) {
    currentContext = context;
    context.its.forEach(test => {
      let obj = {};
      currentTestResult = new TestResultClass(test);
      context.beforeEachChain.forEach(be => be.call(obj));
      test[1].call(obj);
      context.afterEachChain.forEach(ae => ae.call(obj));
      results.addResult(currentTestResult);
      currentTestResult = null;

      spies.forEach(s => {
        s.object[s.methodName] = s.originalFunc;
      });
      spies = [];
    });
    context.contexts.forEach(runContext)
  }

  window.runSpecs = (debug) => {
    debugMode = debug;
    results = new ResultsClass();
    // parse specs
    parseContext(topContext);

    // run specs
    runContext(topContext);

    let total = results.all.length;
    let totalPlural = total===1? '' : 's';

    if(results.failed.length > 0) {
      results.failed.forEach(result => {
        if(!debugMode) {
          consoleFailMessage(failMessage(result));
        }
      });
      let failCount = results.failed.length;
      console.log('\nTests Finished: %d Failure%s / %d Test%s', failCount, failCount===1?'':'s', total, totalPlural);
    } else {
      results.all.forEach( result => {
        console.log('Passed: %s', result.testPath.join(' '));
      });
      console.log('\nTests Finished: %d Successes%s / %d Test%s', total, totalPlural, total, totalPlural);
    }
    if(results.noExpectations.length > 0) {
      results.noExpectations.forEach(result => {
        console.warn('No Expectations in: \n%s', indentLines(result.testPath).join('\n'), result.test[1]);
      });
    }

    return results;
  };
})();

<commit_msg>Improve debug error messages and stack trace logic<commit_after>// Custom test suite (without webpack) by Jason Steck
(function(){
  const PASS = 1;
  const FAIL = 0;
  const NO_EXPECTATIONS = -1;

  let topContext = {
    descriptionChain: [],
    beforeEachChain: [],
    afterEachChain: [],
    its: [],
    describes: [],
    contexts: [],
  };
  /*  during setup  */
  let currentContext = topContext;

  window.describe = (str, func) => {
    currentContext.describes.push([str, func]);
  };

  window.beforeEach = (func) => {
    currentContext.beforeEachChain.push(func);
  };

  window.it = (str, func) => {
    if(typeof func !== 'function') throw new Error(`Missing function in 'it' block of "${str}"`);
    currentContext.its.push([str, func]);
  };

  window.afterEach = (func) => {
    currentContext.afterEachChain.unshift(func);
  };

  /*  during tests  */
  let debugMode = false;
  let spies = [];

  function ResultsClass() {
    this.all = [];
    this.failed = [];
    this.noExpectations = [];
  }
  ResultsClass.prototype.addResult = function (testResult){
    this.all.push(testResult);
    if(testResult.result === FAIL) {
      this.failed.push(testResult);
    } else if(testResult.result === NO_EXPECTATIONS) {
      this.noExpectations.push(testResult);
    }
  };

  function TestResultClass(test) {
    this.testPath = null;
    this.test = test;
    this.result = NO_EXPECTATIONS;
    this.failReasons = [];

    this.testPath = currentContext.descriptionChain.slice(0);
    this.testPath.push(test[0]);
  }
  TestResultClass.prototype.failExpectation = function(reason, stack){
    this.result = FAIL;
    this.failReasons.push(reason+'\n'+stack);
  };
  TestResultClass.prototype.passExpectation = function() {
    if(this.result === NO_EXPECTATIONS) {
      this.result = PASS;
    }
  };

  let results = null;
  let currentTestResult = null;

  function getFileNameFromErrorLine(line) {
    return line.match(/\((.*):\d+:\d+\)/)[1];
  }

  function getErrorStack() {
    let errorLines = (new Error()).stack.split('\n');
    let currentFile = getFileNameFromErrorLine(errorLines[1]);
    for(let i=2;i<errorLines.length;i++) {
      let file = getFileNameFromErrorLine(errorLines[i]);
      if(file !== currentFile) {
        return errorLines[i];
      }
    }

    return errorLines.slice(5,6).join('\n'); //fallback
  }
  window.err = getErrorStack;

  function failWithConsole(msg) {
    currentTestResult.failExpectation(msg, getErrorStack());
    if(debugMode){
      consoleFailMessage(failMessage(currentTestResult));
      return true;
    }
    return false;
  }

  function isEqual(a,b) {
    if(typeof a !== typeof b) return false;
    if(a === Object(a)){
      return objectsEqual(a,b);
    } else if(Array.isArray(a)) {
      return arraysEqual(a,b)
    } else {
      return a == b;
    }
  }

  function objectsEqual(a, b) {
    let aProps = Object.getOwnPropertyNames(a);
    let bProps = Object.getOwnPropertyNames(b);

    if (aProps.length !== bProps.length) return false;

    for (let i = 0; i < aProps.length; i++) {
      let propName = aProps[i];

      if (!isEqual(a[propName], b[propName])) {
        return false;
      }
    }
    return true;
  }

  function arraysEqual(a, b) {
    if (a === b) return true;
    if (a.length !== b.length) return false;

    for (let i = 0; i < a.length; i++) {
      if (a[i] !== b[i]) return false;
    }
    return true;
  }

  function getOutputFormat(exp) {
    if(typeof exp === 'function') {
      return exp.toString();
    }
    return JSON.stringify(exp);
  }

  function toEqual(actual, expected, not) {
    if(isEqual(actual,expected) ^ not){
      currentTestResult.passExpectation();
    } else {
      let a = getOutputFormat(actual);
      let b = getOutputFormat(expected);
      currentTestResult.failExpectation(`Expected ${a} \nto equal ${b}`, getErrorStack());
      if (debugMode) {
        consoleFailMessage(failMessage(currentTestResult));
        debugger;
      }
    }
  }

  function toBe(actual, expected, not) {
    if((actual === expected) ^ not){
      currentTestResult.passExpectation();
    } else {
      let a = getOutputFormat(actual);
      let b = getOutputFormat(expected);
      currentTestResult.failExpectation(`Expected ${a} \n   to be ${b}`, getErrorStack());
      if(debugMode){
        consoleFailMessage(failMessage(currentTestResult));
        debugger;
      }
    }
  }

  function toThrow(actual, exception, not) {
    let threw = false;
    let correctlyThrew = false;
    let error = null;
    try {
      actual();
    } catch (err) {
      error = err;
      if(err == exception ||
        (err.name !== undefined &&
        err.message!== undefined &&
        err.name === exception.name &&
        isEqual(err.message, exception.message))) {

        correctlyThrew = true;
      }
      threw = true;
    }
    if(not) {
      if(correctlyThrew) {
        if(failWithConsole(`Expected ${actual} \nnot to throw "${exception}"\n but it did`)) debugger;
      } else {
        currentTestResult.passExpectation();
      }
    } else {
      if(correctlyThrew) {
        currentTestResult.passExpectation();
      } else if(threw) {
        let notString = not?'not':'';
        if(failWithConsole(`Expected ${actual} \n${notString}to throw "${exception}"\n but got "${error}"`)) debugger;
      } else {
        if(failWithConsole(`Expected ${actual} \nto throw "${exception}" but didn't get anything`)) debugger;
      }
    }
  }

  window.expect = (actual) => {
    return {
      not: {
        toThrow: expected => {
          toThrow(actual, expected, true);
        },
        toEqual: expected => {
          toEqual(actual, expected, true);
        },
        toBe: expected => {
          toBe(actual, expected, true);
        },
      },
      toThrow: exception => {
        toThrow(actual, exception, false);
      },
      toEqual: expected => {
        toEqual(actual, expected, false);
      },
      toBe: expected => {
        toBe(actual, expected, false);
      },
    }
  };

  function ensureSpy(str, obj) {
    if(!(obj && obj[str] && obj[str]._isSpy)) {
      return obj[str] = newSpyGuy(str, obj);
    }
    return obj[str];
  }

  function newSpyGuy(str, obj) {
    function spyGuy(...args){
      let returnValue = undefined;
      if(self.callFake) {
        returnValue = self.callFake.apply(this, args);
      }
      if(self.returnValue) {
        returnValue = self.returnValue;
      }
      return returnValue;
    }
    let self = spyGuy;
    spyGuy._isSpy = true;
    spyGuy.methodName = str;
    spyGuy.object = obj;
    spyGuy.originalFunc = obj && obj[str];
    spyGuy.callFake = null;
    spyGuy.returnValue = null;

    spies.push(spyGuy);
    return spyGuy;
  }

  window.stub = function(obj) {
    return new Proxy({}, {
      get: function(_, str) {
        let spyGuy = ensureSpy(str, obj);
        function spyHandler(){}
        spyHandler.toReturn = val => {
          spyGuy.returnValue = val;
          return spyHandler;
        };
        return spyHandler;
      },
      set: function(_, str, val){
        ensureSpy(str, obj);
        if(typeof val === 'function') {
          obj[str].callFake = val;
        }
      },
    });
  };

  function indentLines(lines, pad = '  '){
    let padding = '';
    return lines.map(desc => {
      return [padding+desc, padding+=pad][0];
    })
  }

  function failMessage(testResult, showAllLines) {
    let failReasons = testResult.failReasons;
    if(!showAllLines) {
      failReasons = [failReasons[failReasons.length-1]];
    }
    let descriptions = indentLines(testResult.testPath).join('\n');
    return `${descriptions} \n${failReasons.join('\n')}`;
  }

  function consoleFailMessage(msg) {
    console.log('%c Failure:', 'color: red; font-weight: bold;');
    console.log(msg);
  }

  /*  spec execution  */
  function parseContext(context) {
    let prevContext = currentContext;
    context.describes.forEach(desc => {
      let newContext = {
        descriptionChain: context.descriptionChain.slice(0),
        beforeEachChain: context.beforeEachChain.slice(0),
        afterEachChain: context.afterEachChain.slice(0),
        its: [],
        describes: [],
        contexts: [],
      };
      newContext.descriptionChain.push(desc[0]);
      context.contexts.push(newContext);
      currentContext = newContext;
      desc[1]();
      parseContext(newContext);
    });
    currentContext = prevContext;
  }

  function runContext(context) {
    currentContext = context;
    context.its.forEach(test => {
      let obj = {};
      currentTestResult = new TestResultClass(test);
      context.beforeEachChain.forEach(be => be.call(obj));
      test[1].call(obj);
      context.afterEachChain.forEach(ae => ae.call(obj));
      results.addResult(currentTestResult);
      currentTestResult = null;

      spies.forEach(s => {
        s.object[s.methodName] = s.originalFunc;
      });
      spies = [];
    });
    context.contexts.forEach(runContext)
  }

  window.runSpecs = (debug) => {
    debugMode = debug;
    results = new ResultsClass();
    // parse specs
    parseContext(topContext);

    // run specs
    runContext(topContext);

    let total = results.all.length;
    let totalPlural = total===1? '' : 's';

    if(results.failed.length > 0) {
      results.failed.forEach(result => {
        if(!debugMode) {
          consoleFailMessage(failMessage(result, true));
        }
      });
      let failCount = results.failed.length;
      console.log('\nTests Finished: %d Failure%s / %d Test%s', failCount, failCount===1?'':'s', total, totalPlural);
    } else {
      results.all.forEach( result => {
        console.log('Passed: %s', result.testPath.join(' '));
      });
      console.log('\nTests Finished: %d Successes%s / %d Test%s', total, totalPlural, total, totalPlural);
    }
    if(results.noExpectations.length > 0) {
      results.noExpectations.forEach(result => {
        console.warn('No Expectations in: \n%s', indentLines(result.testPath).join('\n'), result.test[1]);
      });
    }

    return results;
  };
})();

<|endoftext|>


<commit_before>'use strict';

const fs   = require('fs');
const path = require('path');

const BASE_DIR  = process.cwd();
const PARTS_DIR = './img/ika';
const SCHEME_SRC_DIR  = './src/script/data/_parts';
const SCHEME_DIST_DIR = './src/script/data/parts';

if (path.basename(BASE_DIR) !== 'ika-maker') {
  console.log('Execute from project root!');
  process.exit(1);
}

console.log(`Generate ${SCHEME_DIST_DIR}.js`);

/**
 * このオブジェクトを、存在する画像ファイルから補完する
 *
 */
let _partsScheme = require(path.resolve(BASE_DIR, SCHEME_SRC_DIR));
let getPartsSchemebyAppType = (_appType) => {
  let partsScheme = JSON.parse(JSON.stringify(_partsScheme));

  Object.keys(partsScheme).forEach((parts) => {
    let appType = (parts === 'bg' || parts === 'eyes') ? 'cmn' : _appType;
    let partsPath = path.resolve(PARTS_DIR, appType, parts);
    let partsList = fs.readdirSync(partsPath);
    let selectType = partsScheme[parts].selectType;

    if (selectType === 'TYPE' || selectType === 'COLOR') {
      partsList
        .sort(_sortByFileNo)
        .forEach((file) => {
          partsScheme[parts].items.push(_getElementByFileName(file, `${PARTS_DIR}/${appType}/${parts}`));
        });
    }

    if (selectType === 'TYPE_COLOR') {
      partsList.forEach((type) => {
        let colorsList = fs.readdirSync(path.resolve(PARTS_DIR, appType, parts, type));
        let colorItems = colorsList
          .sort(_sortByFileNo)
          .map((file) => {
            return _getElementByFileName(file, `${PARTS_DIR}/${appType}/${parts}/${type}`);
          });

        partsScheme[parts].items.push({
          id:    type|0,
          items: colorItems
        });
      });
    }
  });

  return partsScheme;
};

let ret = {
  girl: getPartsSchemebyAppType('girl'),
  boy:  getPartsSchemebyAppType('boy'),
};

let data = `export default ${JSON.stringify(ret, null, 2)};`;

fs.writeFileSync(`${path.resolve(BASE_DIR, SCHEME_DIST_DIR)}.js`, data);
console.log('Done!');

function _getElementByFileName(file, path) {
  return {
    id:   file.split('.')[0]|0,
    path: `${path}/${file}`
  };
}

function _sortByFileNo(a, b) {
  return parseInt(a, 10) > parseInt(b, 10) ? 1 : -1;
}
<commit_msg>shリファクタ<commit_after>'use strict';

const fs   = require('fs');
const path = require('path');

const BASE_DIR  = process.cwd();
const PARTS_DIR = './img/ika';
const SCHEME_SRC_DIR  = './src/script/data/_parts';
const SCHEME_DIST_DIR = './src/script/data/parts';

if (path.basename(BASE_DIR) !== 'ika-maker') {
  console.log('Execute from project root!');
  process.exit(1);
}

console.log(`Generate ${SCHEME_DIST_DIR}.js`);

/**
 * このオブジェクトを、存在する画像ファイルから補完する
 *
 */
const PARTS_SCHEME = require(path.resolve(BASE_DIR, SCHEME_SRC_DIR));
const cmnItemMap = { bg: 1, eyes: 1 };

let data = {
  girl: _getPartsSchemebyAppType('girl'),
  boy:  _getPartsSchemebyAppType('boy'),
};
data = `export default ${JSON.stringify(data, null, 2)};`;

fs.writeFileSync(`${path.resolve(BASE_DIR, SCHEME_DIST_DIR)}.js`, data);
console.log('Done!');

function _getPartsSchemebyAppType(appType) {
  let partsScheme = JSON.parse(JSON.stringify(PARTS_SCHEME));

  Object.keys(partsScheme).forEach((parts) => {
    let appPartsType = parts in cmnItemMap ? 'cmn' : appType;
    let partsPath = path.resolve(PARTS_DIR, appPartsType, parts);
    let partsList = fs.readdirSync(partsPath);
    let selectType = partsScheme[parts].selectType;

    if (selectType === 'TYPE' || selectType === 'COLOR') {
      partsList
        .sort(_sortByFileNo)
        .forEach((file) => {
          partsScheme[parts].items.push(_getElementByFileName(file, `${PARTS_DIR}/${appPartsType}/${parts}`));
        });
    }

    if (selectType === 'TYPE_COLOR') {
      partsList.forEach((type) => {
        let colorsList = fs.readdirSync(path.resolve(PARTS_DIR, appPartsType, parts, type));
        let colorItems = colorsList
          .sort(_sortByFileNo)
          .map((file) => {
            return _getElementByFileName(file, `${PARTS_DIR}/${appPartsType}/${parts}/${type}`);
          });

        partsScheme[parts].items.push({
          id:    type|0,
          items: colorItems
        });
      });
    }
  });

  return partsScheme;
}

function _getElementByFileName(file, path) {
  return {
    id:   file.split('.')[0]|0,
    path: `${path}/${file}`
  };
}

function _sortByFileNo(a, b) {
  return parseInt(a, 10) > parseInt(b, 10) ? 1 : -1;
}
<|endoftext|>